fab119b260a64f40ea3db632486e0823a0c0f493
markd
  Tue Jun 30 18:33:39 2020 +0000
forgot to add test driver

diff --git src/gfServer/tests/dynTester src/gfServer/tests/dynTester
new file mode 100755
index 0000000..ece8d6c
--- /dev/null
+++ src/gfServer/tests/dynTester
@@ -0,0 +1,143 @@
+#!/usr/bin/env python3
+
+# Test driver for dynamic server.  This is required because of the need to interact on stdin/stdout
+# using a somewhat binary protocol.
+
+import sys
+import argparse
+import subprocess
+
+debug = False
+
+def parseArgs():
+    usage = """Run a test of qfServer dynserver"""
+    parser = argparse.ArgumentParser(description=usage)
+    parser.add_argument('--debug', action="store_true", default=False,
+                        help="enable debug tracing")
+    parser.add_argument('rootDir', type=str,
+                        help="data root directory")
+    parser.add_argument('queryType', type=str, choices=("query", "protQuery", "transQuery"),
+                        help="query request: query, protQuery, or transQuery")
+    parser.add_argument('genome', type=str,
+                        help="genome name")
+    parser.add_argument('queryFa', type=str,
+                        help="query fasta")
+    parser.add_argument('resultsOut', type=str,
+                        help="out is saved here for checking ")
+    args = parser.parse_args()
+    global debug
+    debug = args.debug
+    return args
+
+gfSignature = "0ddf270562684f29"
+
+def readFastaSeqsFh(faFh):
+    """read from one sequence from fasta"""
+    seqs = []
+    seq = ""
+    for line in faFh:
+        line = line.strip()
+        if line.startswith('>'):
+            if len(seq) > 0:
+                seqs.append(seq)
+                seq = ""
+        elif len(line) > 0:
+            seq = seq + line
+    if len(seq) > 0:
+        seqs.append(bytes(seq, encoding="latin-1"))
+    return seqs
+
+def readFastaSeqs(queryFa):
+    """simplistic FASTA reader, just code here to avoid added dependency"""
+    with open(queryFa) as faFh:
+        return readFastaSeqsFh(faFh)
+
+def readBytes(fh, count):
+    "read specified number of bytes, handing incomplete reads"
+    buf = bytes()
+    while len(buf) < count:
+        resp = fh.read(count - len(buf))
+        if len(resp) == 0:
+            raise Exception("unexpected EOF from server")
+        buf += resp
+    if debug:
+        print("debug: read:", str(buf, encoding="latin-1"), file=sys.stderr)
+    return buf
+
+def writeBytes(fh, buf):
+    "write bytes with debug tracing and byte conversion"
+    if not isinstance(buf, bytes):
+        buf = bytes(buf, encoding="utf8")
+    if debug:
+        print("debug: write:", str(buf, encoding="latin-1"), file=sys.stderr)
+    fh.write(buf)
+
+def netSendString(fh, data):
+    "Send a string down a socket - length byte first. (matches net.c)"
+    fh.write(fh, bytes(len(data)))
+    fh.write(data)
+
+def netRecieveString(fd):
+    "Read string return it (matches net.c)"
+    buf = readBytes(fd, 1)
+    return readBytes(fd, buf[0])
+
+def serverStart(rootDir):
+    "start server process"
+    # unbuffered is required, as protocol is not line-terminate
+    cmd = ["gfServer"]
+    if debug:
+        cmd += ["-log=/dev/stderr", "-debugLog"]
+    cmd += ["dynserver", rootDir]
+    if debug:
+        print("debug: start:", " ".join(cmd), file=sys.stderr)
+    return subprocess.Popen(cmd, bufsize=0,
+                            stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+
+def serverWait(gfServer):
+    "wait for server process to exit"
+    gfServer.wait()
+    if gfServer.returncode != 0:
+        raise Exception("gfServer process exited with {}".format(gfServer.returncode))
+
+def readResults(gfServer, resultsFh):
+    "read the results, which come back using the net string stuff"
+    while True:
+        resp = netRecieveString(gfServer.stdout)
+        if len(resp) > 0:
+            print(str(resp, encoding="latin-1"), file=resultsFh)
+        if resp == b'end':
+            break
+
+def makeQuery(gfServer, queryType, genome, seq, resultsFh):
+    "make a query to the server"
+    query = "{}{} {} {}\n".format(gfSignature, queryType, len(seq), genome)
+    print(query, file=resultsFh)
+    writeBytes(gfServer.stdin, query)
+
+    resp = readBytes(gfServer.stdout, 1)
+    if resp != b"Y":
+        raise Exception("expected 'Y' from gfServer, got '{}'".format(resp))
+    writeBytes(gfServer.stdin, seq)
+    readResults(gfServer, resultsFh)
+
+def queryServer(rootDir, queryType, genome, seq, resultsFh):
+    """on round of starting server, making a query, and stopping"""
+    gfServer = serverStart(rootDir)
+    makeQuery(gfServer, queryType, genome, seq, resultsFh)
+    serverWait(gfServer)
+
+def dynTester(rootDir, queryType, genome, queryFa, resultsFh):
+    "run tests"
+    seqs = readFastaSeqs(queryFa)
+    if len(seqs) == 0:
+        raise Exception("no sequences found in {}".format(queryFa))
+    for seq in seqs:
+        queryServer(rootDir, queryType, genome, seq, resultsFh)
+
+def main():
+    args = parseArgs()
+    with open(args.resultsOut, "w") as resultsFh:
+        dynTester(args.rootDir, args.queryType, args.genome, args.queryFa, resultsFh)
+
+main()