test-commandserver.py
357 lines
| 9.6 KiB
| text/x-python
|
PythonLexer
/ tests / test-commandserver.py
Idan Kamara
|
r14882 | import sys, os, struct, subprocess, cStringIO, re, shutil | ||
Idan Kamara
|
r14770 | |||
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: | ||||
Brodie Rao
|
r16687 | raise EOFError | ||
Idan Kamara
|
r14770 | channel, length = struct.unpack('>cI', data) | ||
if channel in 'IL': | ||||
return channel, length | ||||
else: | ||||
return channel, server.stdout.read(length) | ||||
Brendan Cully
|
r19132 | def sep(text): | ||
return text.replace('\\', '/') | ||||
def runcommand(server, args, output=sys.stdout, error=sys.stderr, input=None, | ||||
outfilter=lambda x: x): | ||||
Mads Kiilerich
|
r15541 | print ' runcommand', ' '.join(args) | ||
Idan Kamara
|
r16117 | sys.stdout.flush() | ||
Idan Kamara
|
r14770 | 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': | ||||
Brendan Cully
|
r19132 | output.write(outfilter(data)) | ||
Idan Kamara
|
r14770 | 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': | ||||
Yuya Nishihara
|
r20630 | ret, = struct.unpack('>i', data) | ||
if ret != 0: | ||||
print ' [%d]' % ret | ||||
return ret | ||||
Idan Kamara
|
r14770 | else: | ||
print "unexpected channel %c: %r" % (ch, data) | ||||
if ch.isupper(): | ||||
return | ||||
def check(func, repopath=None): | ||||
Mads Kiilerich
|
r15541 | |||
print 'testing %s:' % func.__name__ | ||||
Idan Kamara
|
r16117 | sys.stdout.flush() | ||
Idan Kamara
|
r14770 | 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 | ||||
Brodie Rao
|
r16683 | print '%c, %r' % (ch, re.sub('encoding: [a-zA-Z0-9-]+', 'encoding: ***', | ||
data)) | ||||
Idan Kamara
|
r14770 | |||
# 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']) | ||||
Yuya Nishihara
|
r20631 | # negative return code should be masked | ||
runcommand(server, ['id', '-runknown']) | ||||
Idan Kamara
|
r14770 | 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']) | ||||
Idan Kamara
|
r14864 | def cwd(server): | ||
""" check that --cwd doesn't persist between requests """ | ||||
readchannel(server) | ||||
os.mkdir('foo') | ||||
Mads Kiilerich
|
r15542 | f = open('foo/bar', 'wb') | ||
Idan Kamara
|
r14880 | f.write('a') | ||
f.close() | ||||
Idan Kamara
|
r14864 | runcommand(server, ['--cwd', 'foo', 'st', 'bar']) | ||
runcommand(server, ['st', 'foo/bar']) | ||||
os.remove('foo/bar') | ||||
Idan Kamara
|
r14882 | def localhgrc(server): | ||
""" check that local configs for the cached repo aren't inherited when -R | ||||
is used """ | ||||
readchannel(server) | ||||
Brodie Rao
|
r16683 | # the cached repo local hgrc contains ui.foo=bar, so showconfig should | ||
# show it | ||||
Matt Mackall
|
r22086 | runcommand(server, ['showconfig'], outfilter=sep) | ||
Idan Kamara
|
r14882 | |||
# but not for this repo | ||||
runcommand(server, ['init', 'foo']) | ||||
Mads Kiilerich
|
r15542 | runcommand(server, ['-R', 'foo', 'showconfig', 'ui', 'defaults']) | ||
Idan Kamara
|
r14882 | shutil.rmtree('foo') | ||
Idan Kamara
|
r14889 | def hook(**args): | ||
print 'hook talking' | ||||
print 'now try to read something: %r' % sys.stdin.read() | ||||
def hookoutput(server): | ||||
readchannel(server) | ||||
runcommand(server, ['--config', | ||||
Brodie Rao
|
r16683 | 'hooks.pre-identify=python:test-commandserver.hook', | ||
'id'], | ||||
Idan Kamara
|
r14889 | input=cStringIO.StringIO('some input')) | ||
Idan Kamara
|
r14939 | def outsidechanges(server): | ||
readchannel(server) | ||||
Mads Kiilerich
|
r15542 | f = open('a', 'ab') | ||
f.write('a\n') | ||||
f.close() | ||||
Idan Kamara
|
r16114 | runcommand(server, ['status']) | ||
Mads Kiilerich
|
r15542 | os.system('hg ci -Am2') | ||
Idan Kamara
|
r14939 | runcommand(server, ['tip']) | ||
Idan Kamara
|
r16114 | runcommand(server, ['status']) | ||
Idan Kamara
|
r14939 | |||
def bookmarks(server): | ||||
readchannel(server) | ||||
runcommand(server, ['bookmarks']) | ||||
# changes .hg/bookmarks | ||||
os.system('hg bookmark -i bm1') | ||||
os.system('hg bookmark -i bm2') | ||||
runcommand(server, ['bookmarks']) | ||||
# changes .hg/bookmarks.current | ||||
os.system('hg upd bm1 -q') | ||||
runcommand(server, ['bookmarks']) | ||||
Idan Kamara
|
r16115 | runcommand(server, ['bookmarks', 'bm3']) | ||
f = open('a', 'ab') | ||||
f.write('a\n') | ||||
f.close() | ||||
runcommand(server, ['commit', '-Amm']) | ||||
runcommand(server, ['bookmarks']) | ||||
Idan Kamara
|
r14939 | def tagscache(server): | ||
readchannel(server) | ||||
runcommand(server, ['id', '-t', '-r', '0']) | ||||
os.system('hg tag -r 0 foo') | ||||
runcommand(server, ['id', '-t', '-r', '0']) | ||||
Idan Kamara
|
r15989 | def setphase(server): | ||
readchannel(server) | ||||
runcommand(server, ['phase', '-r', '.']) | ||||
os.system('hg phase -r . -p') | ||||
runcommand(server, ['phase', '-r', '.']) | ||||
Idan Kamara
|
r16116 | def rollback(server): | ||
readchannel(server) | ||||
runcommand(server, ['phase', '-r', '.', '-p']) | ||||
f = open('a', 'ab') | ||||
f.write('a\n') | ||||
f.close() | ||||
runcommand(server, ['commit', '-Am.']) | ||||
runcommand(server, ['rollback']) | ||||
runcommand(server, ['phase', '-r', '.']) | ||||
Idan Kamara
|
r16201 | def branch(server): | ||
readchannel(server) | ||||
runcommand(server, ['branch']) | ||||
os.system('hg branch foo') | ||||
runcommand(server, ['branch']) | ||||
os.system('hg branch default') | ||||
Idan Kamara
|
r16202 | def hgignore(server): | ||
readchannel(server) | ||||
f = open('.hgignore', 'ab') | ||||
f.write('') | ||||
f.close() | ||||
runcommand(server, ['commit', '-Am.']) | ||||
f = open('ignored-file', 'ab') | ||||
f.write('') | ||||
f.close() | ||||
f = open('.hgignore', 'ab') | ||||
f.write('ignored-file') | ||||
f.close() | ||||
runcommand(server, ['status', '-i', '-u']) | ||||
Idan Kamara
|
r18757 | def phasecacheafterstrip(server): | ||
readchannel(server) | ||||
# create new head, 5:731265503d86 | ||||
runcommand(server, ['update', '-C', '0']) | ||||
f = open('a', 'ab') | ||||
f.write('a\n') | ||||
f.close() | ||||
runcommand(server, ['commit', '-Am.', 'a']) | ||||
runcommand(server, ['log', '-Gq']) | ||||
# make it public; draft marker moves to 4:7966c8e3734d | ||||
runcommand(server, ['phase', '-p', '.']) | ||||
Brendan Cully
|
r19132 | # load _phasecache.phaseroots | ||
runcommand(server, ['phase', '.'], outfilter=sep) | ||||
Idan Kamara
|
r18757 | |||
# strip 1::4 outside server | ||||
Matt Mackall
|
r19166 | os.system('hg -q --config extensions.mq= strip 1') | ||
Idan Kamara
|
r18757 | |||
# shouldn't raise "7966c8e3734d: no node!" | ||||
runcommand(server, ['branches']) | ||||
Julien Cristau
|
r20330 | def obsolete(server): | ||
readchannel(server) | ||||
runcommand(server, ['up', 'null']) | ||||
runcommand(server, ['phase', '-df', 'tip']) | ||||
Simon Heimberg
|
r20396 | cmd = 'hg debugobsolete `hg log -r tip --template {node}`' | ||
if os.name == 'nt': | ||||
cmd = 'sh -c "%s"' % cmd # run in sh, not cmd.exe | ||||
os.system(cmd) | ||||
Julien Cristau
|
r20330 | runcommand(server, ['log', '--hidden']) | ||
runcommand(server, ['log']) | ||||
Yuya Nishihara
|
r20628 | def mqoutsidechanges(server): | ||
readchannel(server) | ||||
# load repo.mq | ||||
runcommand(server, ['qapplied']) | ||||
os.system('hg qnew 0.diff') | ||||
# repo.mq should be invalidated | ||||
runcommand(server, ['qapplied']) | ||||
Yuya Nishihara
|
r20629 | runcommand(server, ['qpop', '--all']) | ||
os.system('hg qqueue --create foo') | ||||
# repo.mq should be recreated to point to new queue | ||||
runcommand(server, ['qqueue', '--active']) | ||||
Yuya Nishihara
|
r21195 | def getpass(server): | ||
readchannel(server) | ||||
runcommand(server, ['debuggetpass', '--config', 'ui.interactive=True'], | ||||
input=cStringIO.StringIO('1234\n')) | ||||
Yuya Nishihara
|
r20650 | def startwithoutrepo(server): | ||
readchannel(server) | ||||
runcommand(server, ['init', 'repo2']) | ||||
runcommand(server, ['id', '-R', 'repo2']) | ||||
Idan Kamara
|
r14770 | if __name__ == '__main__': | ||
Yuya Nishihara
|
r20649 | os.system('hg init repo') | ||
os.chdir('repo') | ||||
Idan Kamara
|
r14770 | |||
check(hellomessage) | ||||
check(unknowncommand) | ||||
check(checkruncommand) | ||||
check(inputeof) | ||||
check(serverinput) | ||||
Idan Kamara
|
r14864 | check(cwd) | ||
Idan Kamara
|
r14882 | |||
hgrc = open('.hg/hgrc', 'a') | ||||
hgrc.write('[ui]\nfoo=bar\n') | ||||
hgrc.close() | ||||
check(localhgrc) | ||||
Idan Kamara
|
r14889 | check(hookoutput) | ||
Idan Kamara
|
r14939 | check(outsidechanges) | ||
check(bookmarks) | ||||
check(tagscache) | ||||
Idan Kamara
|
r15989 | check(setphase) | ||
Idan Kamara
|
r16116 | check(rollback) | ||
Idan Kamara
|
r16201 | check(branch) | ||
Idan Kamara
|
r16202 | check(hgignore) | ||
Idan Kamara
|
r18757 | check(phasecacheafterstrip) | ||
Julien Cristau
|
r20330 | obs = open('obs.py', 'w') | ||
obs.write('import mercurial.obsolete\nmercurial.obsolete._enabled = True\n') | ||||
obs.close() | ||||
hgrc = open('.hg/hgrc', 'a') | ||||
hgrc.write('[extensions]\nobs=obs.py\n') | ||||
hgrc.close() | ||||
check(obsolete) | ||||
Yuya Nishihara
|
r20628 | hgrc = open('.hg/hgrc', 'a') | ||
hgrc.write('[extensions]\nmq=\n') | ||||
hgrc.close() | ||||
check(mqoutsidechanges) | ||||
Yuya Nishihara
|
r21195 | dbg = open('dbgui.py', 'w') | ||
dbg.write('from mercurial import cmdutil, commands\n' | ||||
'cmdtable = {}\n' | ||||
'command = cmdutil.command(cmdtable)\n' | ||||
Gregory Szorc
|
r21773 | '@command("debuggetpass", norepo=True)\n' | ||
Yuya Nishihara
|
r21195 | 'def debuggetpass(ui):\n' | ||
' ui.write("%s\\n" % ui.getpass())\n') | ||||
dbg.close() | ||||
hgrc = open('.hg/hgrc', 'a') | ||||
hgrc.write('[extensions]\ndbgui=dbgui.py\n') | ||||
hgrc.close() | ||||
check(getpass) | ||||
Yuya Nishihara
|
r20650 | |||
os.chdir('..') | ||||
check(hellomessage) | ||||
check(startwithoutrepo) | ||||