##// END OF EJS Templates
test-commandserver: split helper functions to new hgclient module...
Yuya Nishihara -
r22566:480b7fef default
parent child Browse files
Show More
@@ -0,0 +1,75
1 # A minimal client for Mercurial's command server
2
3 import sys, struct, subprocess, cStringIO
4
5 def connect(path=None):
6 cmdline = ['hg', 'serve', '--cmdserver', 'pipe']
7 if path:
8 cmdline += ['-R', path]
9
10 server = subprocess.Popen(cmdline, stdin=subprocess.PIPE,
11 stdout=subprocess.PIPE)
12
13 return server
14
15 def writeblock(server, data):
16 server.stdin.write(struct.pack('>I', len(data)))
17 server.stdin.write(data)
18 server.stdin.flush()
19
20 def readchannel(server):
21 data = server.stdout.read(5)
22 if not data:
23 raise EOFError
24 channel, length = struct.unpack('>cI', data)
25 if channel in 'IL':
26 return channel, length
27 else:
28 return channel, server.stdout.read(length)
29
30 def sep(text):
31 return text.replace('\\', '/')
32
33 def runcommand(server, args, output=sys.stdout, error=sys.stderr, input=None,
34 outfilter=lambda x: x):
35 print ' runcommand', ' '.join(args)
36 sys.stdout.flush()
37 server.stdin.write('runcommand\n')
38 writeblock(server, '\0'.join(args))
39
40 if not input:
41 input = cStringIO.StringIO()
42
43 while True:
44 ch, data = readchannel(server)
45 if ch == 'o':
46 output.write(outfilter(data))
47 output.flush()
48 elif ch == 'e':
49 error.write(data)
50 error.flush()
51 elif ch == 'I':
52 writeblock(server, input.read(data))
53 elif ch == 'L':
54 writeblock(server, input.readline(data))
55 elif ch == 'r':
56 ret, = struct.unpack('>i', data)
57 if ret != 0:
58 print ' [%d]' % ret
59 return ret
60 else:
61 print "unexpected channel %c: %r" % (ch, data)
62 if ch.isupper():
63 return
64
65 def check(func, repopath=None):
66 print
67 print 'testing %s:' % func.__name__
68 print
69 sys.stdout.flush()
70 server = connect(repopath)
71 try:
72 return func(server)
73 finally:
74 server.stdin.close()
75 server.wait()
@@ -1,357 +1,288
1 import sys, os, struct, subprocess, cStringIO, re, shutil
1 import sys, os, cStringIO, re, shutil
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 sep(text):
29 return text.replace('\\', '/')
30
31 def runcommand(server, args, output=sys.stdout, error=sys.stderr, input=None,
32 outfilter=lambda x: x):
33 print ' runcommand', ' '.join(args)
34 sys.stdout.flush()
35 server.stdin.write('runcommand\n')
36 writeblock(server, '\0'.join(args))
37
2
38 if not input:
3 sys.path.insert(0, os.path.join(os.environ['TESTDIR'], '..', 'contrib'))
39 input = cStringIO.StringIO()
4 from hgclient import readchannel, sep, runcommand, check
40
41 while True:
42 ch, data = readchannel(server)
43 if ch == 'o':
44 output.write(outfilter(data))
45 output.flush()
46 elif ch == 'e':
47 error.write(data)
48 error.flush()
49 elif ch == 'I':
50 writeblock(server, input.read(data))
51 elif ch == 'L':
52 writeblock(server, input.readline(data))
53 elif ch == 'r':
54 ret, = struct.unpack('>i', data)
55 if ret != 0:
56 print ' [%d]' % ret
57 return ret
58 else:
59 print "unexpected channel %c: %r" % (ch, data)
60 if ch.isupper():
61 return
62
63 def check(func, repopath=None):
64 print
65 print 'testing %s:' % func.__name__
66 print
67 sys.stdout.flush()
68 server = connect(repopath)
69 try:
70 return func(server)
71 finally:
72 server.stdin.close()
73 server.wait()
74
5
75 def unknowncommand(server):
6 def unknowncommand(server):
76 server.stdin.write('unknowncommand\n')
7 server.stdin.write('unknowncommand\n')
77
8
78 def hellomessage(server):
9 def hellomessage(server):
79 ch, data = readchannel(server)
10 ch, data = readchannel(server)
80 # escaping python tests output not supported
11 # escaping python tests output not supported
81 print '%c, %r' % (ch, re.sub('encoding: [a-zA-Z0-9-]+', 'encoding: ***',
12 print '%c, %r' % (ch, re.sub('encoding: [a-zA-Z0-9-]+', 'encoding: ***',
82 data))
13 data))
83
14
84 # run an arbitrary command to make sure the next thing the server sends
15 # run an arbitrary command to make sure the next thing the server sends
85 # isn't part of the hello message
16 # isn't part of the hello message
86 runcommand(server, ['id'])
17 runcommand(server, ['id'])
87
18
88 def checkruncommand(server):
19 def checkruncommand(server):
89 # hello block
20 # hello block
90 readchannel(server)
21 readchannel(server)
91
22
92 # no args
23 # no args
93 runcommand(server, [])
24 runcommand(server, [])
94
25
95 # global options
26 # global options
96 runcommand(server, ['id', '--quiet'])
27 runcommand(server, ['id', '--quiet'])
97
28
98 # make sure global options don't stick through requests
29 # make sure global options don't stick through requests
99 runcommand(server, ['id'])
30 runcommand(server, ['id'])
100
31
101 # --config
32 # --config
102 runcommand(server, ['id', '--config', 'ui.quiet=True'])
33 runcommand(server, ['id', '--config', 'ui.quiet=True'])
103
34
104 # make sure --config doesn't stick
35 # make sure --config doesn't stick
105 runcommand(server, ['id'])
36 runcommand(server, ['id'])
106
37
107 # negative return code should be masked
38 # negative return code should be masked
108 runcommand(server, ['id', '-runknown'])
39 runcommand(server, ['id', '-runknown'])
109
40
110 def inputeof(server):
41 def inputeof(server):
111 readchannel(server)
42 readchannel(server)
112 server.stdin.write('runcommand\n')
43 server.stdin.write('runcommand\n')
113 # close stdin while server is waiting for input
44 # close stdin while server is waiting for input
114 server.stdin.close()
45 server.stdin.close()
115
46
116 # server exits with 1 if the pipe closed while reading the command
47 # server exits with 1 if the pipe closed while reading the command
117 print 'server exit code =', server.wait()
48 print 'server exit code =', server.wait()
118
49
119 def serverinput(server):
50 def serverinput(server):
120 readchannel(server)
51 readchannel(server)
121
52
122 patch = """
53 patch = """
123 # HG changeset patch
54 # HG changeset patch
124 # User test
55 # User test
125 # Date 0 0
56 # Date 0 0
126 # Node ID c103a3dec114d882c98382d684d8af798d09d857
57 # Node ID c103a3dec114d882c98382d684d8af798d09d857
127 # Parent 0000000000000000000000000000000000000000
58 # Parent 0000000000000000000000000000000000000000
128 1
59 1
129
60
130 diff -r 000000000000 -r c103a3dec114 a
61 diff -r 000000000000 -r c103a3dec114 a
131 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
62 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
132 +++ b/a Thu Jan 01 00:00:00 1970 +0000
63 +++ b/a Thu Jan 01 00:00:00 1970 +0000
133 @@ -0,0 +1,1 @@
64 @@ -0,0 +1,1 @@
134 +1
65 +1
135 """
66 """
136
67
137 runcommand(server, ['import', '-'], input=cStringIO.StringIO(patch))
68 runcommand(server, ['import', '-'], input=cStringIO.StringIO(patch))
138 runcommand(server, ['log'])
69 runcommand(server, ['log'])
139
70
140 def cwd(server):
71 def cwd(server):
141 """ check that --cwd doesn't persist between requests """
72 """ check that --cwd doesn't persist between requests """
142 readchannel(server)
73 readchannel(server)
143 os.mkdir('foo')
74 os.mkdir('foo')
144 f = open('foo/bar', 'wb')
75 f = open('foo/bar', 'wb')
145 f.write('a')
76 f.write('a')
146 f.close()
77 f.close()
147 runcommand(server, ['--cwd', 'foo', 'st', 'bar'])
78 runcommand(server, ['--cwd', 'foo', 'st', 'bar'])
148 runcommand(server, ['st', 'foo/bar'])
79 runcommand(server, ['st', 'foo/bar'])
149 os.remove('foo/bar')
80 os.remove('foo/bar')
150
81
151 def localhgrc(server):
82 def localhgrc(server):
152 """ check that local configs for the cached repo aren't inherited when -R
83 """ check that local configs for the cached repo aren't inherited when -R
153 is used """
84 is used """
154 readchannel(server)
85 readchannel(server)
155
86
156 # the cached repo local hgrc contains ui.foo=bar, so showconfig should
87 # the cached repo local hgrc contains ui.foo=bar, so showconfig should
157 # show it
88 # show it
158 runcommand(server, ['showconfig'], outfilter=sep)
89 runcommand(server, ['showconfig'], outfilter=sep)
159
90
160 # but not for this repo
91 # but not for this repo
161 runcommand(server, ['init', 'foo'])
92 runcommand(server, ['init', 'foo'])
162 runcommand(server, ['-R', 'foo', 'showconfig', 'ui', 'defaults'])
93 runcommand(server, ['-R', 'foo', 'showconfig', 'ui', 'defaults'])
163 shutil.rmtree('foo')
94 shutil.rmtree('foo')
164
95
165 def hook(**args):
96 def hook(**args):
166 print 'hook talking'
97 print 'hook talking'
167 print 'now try to read something: %r' % sys.stdin.read()
98 print 'now try to read something: %r' % sys.stdin.read()
168
99
169 def hookoutput(server):
100 def hookoutput(server):
170 readchannel(server)
101 readchannel(server)
171 runcommand(server, ['--config',
102 runcommand(server, ['--config',
172 'hooks.pre-identify=python:test-commandserver.hook',
103 'hooks.pre-identify=python:test-commandserver.hook',
173 'id'],
104 'id'],
174 input=cStringIO.StringIO('some input'))
105 input=cStringIO.StringIO('some input'))
175
106
176 def outsidechanges(server):
107 def outsidechanges(server):
177 readchannel(server)
108 readchannel(server)
178 f = open('a', 'ab')
109 f = open('a', 'ab')
179 f.write('a\n')
110 f.write('a\n')
180 f.close()
111 f.close()
181 runcommand(server, ['status'])
112 runcommand(server, ['status'])
182 os.system('hg ci -Am2')
113 os.system('hg ci -Am2')
183 runcommand(server, ['tip'])
114 runcommand(server, ['tip'])
184 runcommand(server, ['status'])
115 runcommand(server, ['status'])
185
116
186 def bookmarks(server):
117 def bookmarks(server):
187 readchannel(server)
118 readchannel(server)
188 runcommand(server, ['bookmarks'])
119 runcommand(server, ['bookmarks'])
189
120
190 # changes .hg/bookmarks
121 # changes .hg/bookmarks
191 os.system('hg bookmark -i bm1')
122 os.system('hg bookmark -i bm1')
192 os.system('hg bookmark -i bm2')
123 os.system('hg bookmark -i bm2')
193 runcommand(server, ['bookmarks'])
124 runcommand(server, ['bookmarks'])
194
125
195 # changes .hg/bookmarks.current
126 # changes .hg/bookmarks.current
196 os.system('hg upd bm1 -q')
127 os.system('hg upd bm1 -q')
197 runcommand(server, ['bookmarks'])
128 runcommand(server, ['bookmarks'])
198
129
199 runcommand(server, ['bookmarks', 'bm3'])
130 runcommand(server, ['bookmarks', 'bm3'])
200 f = open('a', 'ab')
131 f = open('a', 'ab')
201 f.write('a\n')
132 f.write('a\n')
202 f.close()
133 f.close()
203 runcommand(server, ['commit', '-Amm'])
134 runcommand(server, ['commit', '-Amm'])
204 runcommand(server, ['bookmarks'])
135 runcommand(server, ['bookmarks'])
205
136
206 def tagscache(server):
137 def tagscache(server):
207 readchannel(server)
138 readchannel(server)
208 runcommand(server, ['id', '-t', '-r', '0'])
139 runcommand(server, ['id', '-t', '-r', '0'])
209 os.system('hg tag -r 0 foo')
140 os.system('hg tag -r 0 foo')
210 runcommand(server, ['id', '-t', '-r', '0'])
141 runcommand(server, ['id', '-t', '-r', '0'])
211
142
212 def setphase(server):
143 def setphase(server):
213 readchannel(server)
144 readchannel(server)
214 runcommand(server, ['phase', '-r', '.'])
145 runcommand(server, ['phase', '-r', '.'])
215 os.system('hg phase -r . -p')
146 os.system('hg phase -r . -p')
216 runcommand(server, ['phase', '-r', '.'])
147 runcommand(server, ['phase', '-r', '.'])
217
148
218 def rollback(server):
149 def rollback(server):
219 readchannel(server)
150 readchannel(server)
220 runcommand(server, ['phase', '-r', '.', '-p'])
151 runcommand(server, ['phase', '-r', '.', '-p'])
221 f = open('a', 'ab')
152 f = open('a', 'ab')
222 f.write('a\n')
153 f.write('a\n')
223 f.close()
154 f.close()
224 runcommand(server, ['commit', '-Am.'])
155 runcommand(server, ['commit', '-Am.'])
225 runcommand(server, ['rollback'])
156 runcommand(server, ['rollback'])
226 runcommand(server, ['phase', '-r', '.'])
157 runcommand(server, ['phase', '-r', '.'])
227
158
228 def branch(server):
159 def branch(server):
229 readchannel(server)
160 readchannel(server)
230 runcommand(server, ['branch'])
161 runcommand(server, ['branch'])
231 os.system('hg branch foo')
162 os.system('hg branch foo')
232 runcommand(server, ['branch'])
163 runcommand(server, ['branch'])
233 os.system('hg branch default')
164 os.system('hg branch default')
234
165
235 def hgignore(server):
166 def hgignore(server):
236 readchannel(server)
167 readchannel(server)
237 f = open('.hgignore', 'ab')
168 f = open('.hgignore', 'ab')
238 f.write('')
169 f.write('')
239 f.close()
170 f.close()
240 runcommand(server, ['commit', '-Am.'])
171 runcommand(server, ['commit', '-Am.'])
241 f = open('ignored-file', 'ab')
172 f = open('ignored-file', 'ab')
242 f.write('')
173 f.write('')
243 f.close()
174 f.close()
244 f = open('.hgignore', 'ab')
175 f = open('.hgignore', 'ab')
245 f.write('ignored-file')
176 f.write('ignored-file')
246 f.close()
177 f.close()
247 runcommand(server, ['status', '-i', '-u'])
178 runcommand(server, ['status', '-i', '-u'])
248
179
249 def phasecacheafterstrip(server):
180 def phasecacheafterstrip(server):
250 readchannel(server)
181 readchannel(server)
251
182
252 # create new head, 5:731265503d86
183 # create new head, 5:731265503d86
253 runcommand(server, ['update', '-C', '0'])
184 runcommand(server, ['update', '-C', '0'])
254 f = open('a', 'ab')
185 f = open('a', 'ab')
255 f.write('a\n')
186 f.write('a\n')
256 f.close()
187 f.close()
257 runcommand(server, ['commit', '-Am.', 'a'])
188 runcommand(server, ['commit', '-Am.', 'a'])
258 runcommand(server, ['log', '-Gq'])
189 runcommand(server, ['log', '-Gq'])
259
190
260 # make it public; draft marker moves to 4:7966c8e3734d
191 # make it public; draft marker moves to 4:7966c8e3734d
261 runcommand(server, ['phase', '-p', '.'])
192 runcommand(server, ['phase', '-p', '.'])
262 # load _phasecache.phaseroots
193 # load _phasecache.phaseroots
263 runcommand(server, ['phase', '.'], outfilter=sep)
194 runcommand(server, ['phase', '.'], outfilter=sep)
264
195
265 # strip 1::4 outside server
196 # strip 1::4 outside server
266 os.system('hg -q --config extensions.mq= strip 1')
197 os.system('hg -q --config extensions.mq= strip 1')
267
198
268 # shouldn't raise "7966c8e3734d: no node!"
199 # shouldn't raise "7966c8e3734d: no node!"
269 runcommand(server, ['branches'])
200 runcommand(server, ['branches'])
270
201
271 def obsolete(server):
202 def obsolete(server):
272 readchannel(server)
203 readchannel(server)
273
204
274 runcommand(server, ['up', 'null'])
205 runcommand(server, ['up', 'null'])
275 runcommand(server, ['phase', '-df', 'tip'])
206 runcommand(server, ['phase', '-df', 'tip'])
276 cmd = 'hg debugobsolete `hg log -r tip --template {node}`'
207 cmd = 'hg debugobsolete `hg log -r tip --template {node}`'
277 if os.name == 'nt':
208 if os.name == 'nt':
278 cmd = 'sh -c "%s"' % cmd # run in sh, not cmd.exe
209 cmd = 'sh -c "%s"' % cmd # run in sh, not cmd.exe
279 os.system(cmd)
210 os.system(cmd)
280 runcommand(server, ['log', '--hidden'])
211 runcommand(server, ['log', '--hidden'])
281 runcommand(server, ['log'])
212 runcommand(server, ['log'])
282
213
283 def mqoutsidechanges(server):
214 def mqoutsidechanges(server):
284 readchannel(server)
215 readchannel(server)
285
216
286 # load repo.mq
217 # load repo.mq
287 runcommand(server, ['qapplied'])
218 runcommand(server, ['qapplied'])
288 os.system('hg qnew 0.diff')
219 os.system('hg qnew 0.diff')
289 # repo.mq should be invalidated
220 # repo.mq should be invalidated
290 runcommand(server, ['qapplied'])
221 runcommand(server, ['qapplied'])
291
222
292 runcommand(server, ['qpop', '--all'])
223 runcommand(server, ['qpop', '--all'])
293 os.system('hg qqueue --create foo')
224 os.system('hg qqueue --create foo')
294 # repo.mq should be recreated to point to new queue
225 # repo.mq should be recreated to point to new queue
295 runcommand(server, ['qqueue', '--active'])
226 runcommand(server, ['qqueue', '--active'])
296
227
297 def getpass(server):
228 def getpass(server):
298 readchannel(server)
229 readchannel(server)
299 runcommand(server, ['debuggetpass', '--config', 'ui.interactive=True'],
230 runcommand(server, ['debuggetpass', '--config', 'ui.interactive=True'],
300 input=cStringIO.StringIO('1234\n'))
231 input=cStringIO.StringIO('1234\n'))
301
232
302 def startwithoutrepo(server):
233 def startwithoutrepo(server):
303 readchannel(server)
234 readchannel(server)
304 runcommand(server, ['init', 'repo2'])
235 runcommand(server, ['init', 'repo2'])
305 runcommand(server, ['id', '-R', 'repo2'])
236 runcommand(server, ['id', '-R', 'repo2'])
306
237
307 if __name__ == '__main__':
238 if __name__ == '__main__':
308 os.system('hg init repo')
239 os.system('hg init repo')
309 os.chdir('repo')
240 os.chdir('repo')
310
241
311 check(hellomessage)
242 check(hellomessage)
312 check(unknowncommand)
243 check(unknowncommand)
313 check(checkruncommand)
244 check(checkruncommand)
314 check(inputeof)
245 check(inputeof)
315 check(serverinput)
246 check(serverinput)
316 check(cwd)
247 check(cwd)
317
248
318 hgrc = open('.hg/hgrc', 'a')
249 hgrc = open('.hg/hgrc', 'a')
319 hgrc.write('[ui]\nfoo=bar\n')
250 hgrc.write('[ui]\nfoo=bar\n')
320 hgrc.close()
251 hgrc.close()
321 check(localhgrc)
252 check(localhgrc)
322 check(hookoutput)
253 check(hookoutput)
323 check(outsidechanges)
254 check(outsidechanges)
324 check(bookmarks)
255 check(bookmarks)
325 check(tagscache)
256 check(tagscache)
326 check(setphase)
257 check(setphase)
327 check(rollback)
258 check(rollback)
328 check(branch)
259 check(branch)
329 check(hgignore)
260 check(hgignore)
330 check(phasecacheafterstrip)
261 check(phasecacheafterstrip)
331 obs = open('obs.py', 'w')
262 obs = open('obs.py', 'w')
332 obs.write('import mercurial.obsolete\nmercurial.obsolete._enabled = True\n')
263 obs.write('import mercurial.obsolete\nmercurial.obsolete._enabled = True\n')
333 obs.close()
264 obs.close()
334 hgrc = open('.hg/hgrc', 'a')
265 hgrc = open('.hg/hgrc', 'a')
335 hgrc.write('[extensions]\nobs=obs.py\n')
266 hgrc.write('[extensions]\nobs=obs.py\n')
336 hgrc.close()
267 hgrc.close()
337 check(obsolete)
268 check(obsolete)
338 hgrc = open('.hg/hgrc', 'a')
269 hgrc = open('.hg/hgrc', 'a')
339 hgrc.write('[extensions]\nmq=\n')
270 hgrc.write('[extensions]\nmq=\n')
340 hgrc.close()
271 hgrc.close()
341 check(mqoutsidechanges)
272 check(mqoutsidechanges)
342 dbg = open('dbgui.py', 'w')
273 dbg = open('dbgui.py', 'w')
343 dbg.write('from mercurial import cmdutil, commands\n'
274 dbg.write('from mercurial import cmdutil, commands\n'
344 'cmdtable = {}\n'
275 'cmdtable = {}\n'
345 'command = cmdutil.command(cmdtable)\n'
276 'command = cmdutil.command(cmdtable)\n'
346 '@command("debuggetpass", norepo=True)\n'
277 '@command("debuggetpass", norepo=True)\n'
347 'def debuggetpass(ui):\n'
278 'def debuggetpass(ui):\n'
348 ' ui.write("%s\\n" % ui.getpass())\n')
279 ' ui.write("%s\\n" % ui.getpass())\n')
349 dbg.close()
280 dbg.close()
350 hgrc = open('.hg/hgrc', 'a')
281 hgrc = open('.hg/hgrc', 'a')
351 hgrc.write('[extensions]\ndbgui=dbgui.py\n')
282 hgrc.write('[extensions]\ndbgui=dbgui.py\n')
352 hgrc.close()
283 hgrc.close()
353 check(getpass)
284 check(getpass)
354
285
355 os.chdir('..')
286 os.chdir('..')
356 check(hellomessage)
287 check(hellomessage)
357 check(startwithoutrepo)
288 check(startwithoutrepo)
General Comments 0
You need to be logged in to leave comments. Login now