diff --git a/tests/test-commandserver.py b/tests/test-commandserver.py new file mode 100644 --- /dev/null +++ b/tests/test-commandserver.py @@ -0,0 +1,130 @@ +import sys, os, struct, subprocess, cStringIO, re + +def connect(path=None): + cmdline = ['hg', 'serve', '--cmdserver', 'pipe'] + if path: + cmdline += ['-R', path] + + server = subprocess.Popen(cmdline, stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + + return server + +def writeblock(server, data): + server.stdin.write(struct.pack('>I', len(data))) + server.stdin.write(data) + server.stdin.flush() + +def readchannel(server): + data = server.stdout.read(5) + if not data: + raise EOFError() + channel, length = struct.unpack('>cI', data) + if channel in 'IL': + return channel, length + else: + return channel, server.stdout.read(length) + +def runcommand(server, args, output=sys.stdout, error=sys.stderr, input=None): + server.stdin.write('runcommand\n') + writeblock(server, '\0'.join(args)) + + if not input: + input = cStringIO.StringIO() + + while True: + ch, data = readchannel(server) + if ch == 'o': + output.write(data) + output.flush() + elif ch == 'e': + error.write(data) + error.flush() + elif ch == 'I': + writeblock(server, input.read(data)) + elif ch == 'L': + writeblock(server, input.readline(data)) + elif ch == 'r': + return struct.unpack('>i', data)[0] + else: + print "unexpected channel %c: %r" % (ch, data) + if ch.isupper(): + return + +def check(func, repopath=None): + server = connect(repopath) + try: + return func(server) + finally: + server.stdin.close() + server.wait() + +def unknowncommand(server): + server.stdin.write('unknowncommand\n') + +def hellomessage(server): + ch, data = readchannel(server) + # escaping python tests output not supported + print '%c, %r' % (ch, re.sub('encoding: [a-zA-Z0-9-]+', 'encoding: ***', data)) + + # run an arbitrary command to make sure the next thing the server sends + # isn't part of the hello message + runcommand(server, ['id']) + +def checkruncommand(server): + # hello block + readchannel(server) + + # no args + runcommand(server, []) + + # global options + runcommand(server, ['id', '--quiet']) + + # make sure global options don't stick through requests + runcommand(server, ['id']) + + # --config + runcommand(server, ['id', '--config', 'ui.quiet=True']) + + # make sure --config doesn't stick + runcommand(server, ['id']) + +def inputeof(server): + readchannel(server) + server.stdin.write('runcommand\n') + # close stdin while server is waiting for input + server.stdin.close() + + # server exits with 1 if the pipe closed while reading the command + print 'server exit code =', server.wait() + +def serverinput(server): + readchannel(server) + + patch = """ +# HG changeset patch +# User test +# Date 0 0 +# Node ID c103a3dec114d882c98382d684d8af798d09d857 +# Parent 0000000000000000000000000000000000000000 +1 + +diff -r 000000000000 -r c103a3dec114 a +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/a Thu Jan 01 00:00:00 1970 +0000 +@@ -0,0 +1,1 @@ ++1 +""" + + runcommand(server, ['import', '-'], input=cStringIO.StringIO(patch)) + runcommand(server, ['log']) + +if __name__ == '__main__': + os.system('hg init') + + check(hellomessage) + check(unknowncommand) + check(checkruncommand) + check(inputeof) + check(serverinput) diff --git a/tests/test-commandserver.py.out b/tests/test-commandserver.py.out new file mode 100644 --- /dev/null +++ b/tests/test-commandserver.py.out @@ -0,0 +1,38 @@ +o, 'capabilities: getencoding runcommand\nencoding: ***' +000000000000 tip +abort: unknown command unknowncommand +Mercurial Distributed SCM + +basic commands: + + add add the specified files on the next commit + annotate show changeset information by line for each file + clone make a copy of an existing repository + commit commit the specified files or all outstanding changes + diff diff repository (or selected files) + export dump the header and diffs for one or more changesets + forget forget the specified files on the next commit + init create a new repository in the given directory + log show revision history of entire repository or files + merge merge working directory with another revision + pull pull changes from the specified source + push push changes to the specified destination + remove remove the specified files on the next commit + serve start stand-alone webserver + status show changed files in the working directory + summary summarize working directory state + update update working directory (or switch revisions) + +use "hg help" for the full list of commands or "hg -v" for details +000000000000 +000000000000 tip +000000000000 +000000000000 tip +server exit code = 1 +applying patch from stdin +changeset: 0:eff892de26ec +tag: tip +user: test +date: Thu Jan 01 00:00:00 1970 +0000 +summary: 1 +