|
1 import sys, os, struct, subprocess, cStringIO, re |
|
2 |
|
3 def connect(path=None): |
|
4 cmdline = ['hg', 'serve', '--cmdserver', 'pipe'] |
|
5 if path: |
|
6 cmdline += ['-R', path] |
|
7 |
|
8 server = subprocess.Popen(cmdline, stdin=subprocess.PIPE, |
|
9 stdout=subprocess.PIPE) |
|
10 |
|
11 return server |
|
12 |
|
13 def writeblock(server, data): |
|
14 server.stdin.write(struct.pack('>I', len(data))) |
|
15 server.stdin.write(data) |
|
16 server.stdin.flush() |
|
17 |
|
18 def readchannel(server): |
|
19 data = server.stdout.read(5) |
|
20 if not data: |
|
21 raise EOFError() |
|
22 channel, length = struct.unpack('>cI', data) |
|
23 if channel in 'IL': |
|
24 return channel, length |
|
25 else: |
|
26 return channel, server.stdout.read(length) |
|
27 |
|
28 def runcommand(server, args, output=sys.stdout, error=sys.stderr, input=None): |
|
29 server.stdin.write('runcommand\n') |
|
30 writeblock(server, '\0'.join(args)) |
|
31 |
|
32 if not input: |
|
33 input = cStringIO.StringIO() |
|
34 |
|
35 while True: |
|
36 ch, data = readchannel(server) |
|
37 if ch == 'o': |
|
38 output.write(data) |
|
39 output.flush() |
|
40 elif ch == 'e': |
|
41 error.write(data) |
|
42 error.flush() |
|
43 elif ch == 'I': |
|
44 writeblock(server, input.read(data)) |
|
45 elif ch == 'L': |
|
46 writeblock(server, input.readline(data)) |
|
47 elif ch == 'r': |
|
48 return struct.unpack('>i', data)[0] |
|
49 else: |
|
50 print "unexpected channel %c: %r" % (ch, data) |
|
51 if ch.isupper(): |
|
52 return |
|
53 |
|
54 def check(func, repopath=None): |
|
55 server = connect(repopath) |
|
56 try: |
|
57 return func(server) |
|
58 finally: |
|
59 server.stdin.close() |
|
60 server.wait() |
|
61 |
|
62 def unknowncommand(server): |
|
63 server.stdin.write('unknowncommand\n') |
|
64 |
|
65 def hellomessage(server): |
|
66 ch, data = readchannel(server) |
|
67 # escaping python tests output not supported |
|
68 print '%c, %r' % (ch, re.sub('encoding: [a-zA-Z0-9-]+', 'encoding: ***', data)) |
|
69 |
|
70 # run an arbitrary command to make sure the next thing the server sends |
|
71 # isn't part of the hello message |
|
72 runcommand(server, ['id']) |
|
73 |
|
74 def checkruncommand(server): |
|
75 # hello block |
|
76 readchannel(server) |
|
77 |
|
78 # no args |
|
79 runcommand(server, []) |
|
80 |
|
81 # global options |
|
82 runcommand(server, ['id', '--quiet']) |
|
83 |
|
84 # make sure global options don't stick through requests |
|
85 runcommand(server, ['id']) |
|
86 |
|
87 # --config |
|
88 runcommand(server, ['id', '--config', 'ui.quiet=True']) |
|
89 |
|
90 # make sure --config doesn't stick |
|
91 runcommand(server, ['id']) |
|
92 |
|
93 def inputeof(server): |
|
94 readchannel(server) |
|
95 server.stdin.write('runcommand\n') |
|
96 # close stdin while server is waiting for input |
|
97 server.stdin.close() |
|
98 |
|
99 # server exits with 1 if the pipe closed while reading the command |
|
100 print 'server exit code =', server.wait() |
|
101 |
|
102 def serverinput(server): |
|
103 readchannel(server) |
|
104 |
|
105 patch = """ |
|
106 # HG changeset patch |
|
107 # User test |
|
108 # Date 0 0 |
|
109 # Node ID c103a3dec114d882c98382d684d8af798d09d857 |
|
110 # Parent 0000000000000000000000000000000000000000 |
|
111 1 |
|
112 |
|
113 diff -r 000000000000 -r c103a3dec114 a |
|
114 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 |
|
115 +++ b/a Thu Jan 01 00:00:00 1970 +0000 |
|
116 @@ -0,0 +1,1 @@ |
|
117 +1 |
|
118 """ |
|
119 |
|
120 runcommand(server, ['import', '-'], input=cStringIO.StringIO(patch)) |
|
121 runcommand(server, ['log']) |
|
122 |
|
123 if __name__ == '__main__': |
|
124 os.system('hg init') |
|
125 |
|
126 check(hellomessage) |
|
127 check(unknowncommand) |
|
128 check(checkruncommand) |
|
129 check(inputeof) |
|
130 check(serverinput) |