##// END OF EJS Templates
run-tests.py: avoid using popen2.Popen4 - use subprocess instead...
Mads Kiilerich -
r7813:076401cf default
parent child Browse files
Show More
@@ -1,671 +1,686 b''
1 1 #!/usr/bin/env python
2 2 #
3 3 # run-tests.py - Run a set of tests on Mercurial
4 4 #
5 5 # Copyright 2006 Matt Mackall <mpm@selenic.com>
6 6 #
7 7 # This software may be used and distributed according to the terms
8 8 # of the GNU General Public License, incorporated herein by reference.
9 9
10 10 import difflib
11 11 import errno
12 12 import optparse
13 13 import os
14 import popen2
14 try:
15 import subprocess
16 subprocess.Popen # trigger ImportError early
17 closefds = os.name == 'posix'
18 def Popen4(cmd, bufsize=-1):
19 p = subprocess.Popen(cmd, shell=True, bufsize=bufsize,
20 close_fds=closefds,
21 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
22 stderr=subprocess.STDOUT)
23 p.fromchild = p.stdout
24 p.tochild = p.stdin
25 p.childerr = p.stderr
26 return p
27 except ImportError:
28 subprocess = None
29 from popen2 import Popen4
15 30 import shutil
16 31 import signal
17 32 import sys
18 33 import tempfile
19 34 import time
20 35
21 36 # reserved exit code to skip test (used by hghave)
22 37 SKIPPED_STATUS = 80
23 38 SKIPPED_PREFIX = 'skipped: '
24 39
25 40 required_tools = ["python", "diff", "grep", "unzip", "gunzip", "bunzip2", "sed"]
26 41
27 42 defaults = {
28 43 'jobs': ('HGTEST_JOBS', 1),
29 44 'timeout': ('HGTEST_TIMEOUT', 180),
30 45 'port': ('HGTEST_PORT', 20059),
31 46 }
32 47
33 48 parser = optparse.OptionParser("%prog [options] [tests]")
34 49 parser.add_option("-C", "--annotate", action="store_true",
35 50 help="output files annotated with coverage")
36 51 parser.add_option("--child", type="int",
37 52 help="run as child process, summary to given fd")
38 53 parser.add_option("-c", "--cover", action="store_true",
39 54 help="print a test coverage report")
40 55 parser.add_option("-f", "--first", action="store_true",
41 56 help="exit on the first test failure")
42 57 parser.add_option("-i", "--interactive", action="store_true",
43 58 help="prompt to accept changed output")
44 59 parser.add_option("-j", "--jobs", type="int",
45 60 help="number of jobs to run in parallel"
46 61 " (default: $%s or %d)" % defaults['jobs'])
47 62 parser.add_option("--keep-tmpdir", action="store_true",
48 63 help="keep temporary directory after running tests"
49 64 " (best used with --tmpdir)")
50 65 parser.add_option("-R", "--restart", action="store_true",
51 66 help="restart at last error")
52 67 parser.add_option("-p", "--port", type="int",
53 68 help="port on which servers should listen"
54 69 " (default: $%s or %d)" % defaults['port'])
55 70 parser.add_option("-r", "--retest", action="store_true",
56 71 help="retest failed tests")
57 72 parser.add_option("-s", "--cover_stdlib", action="store_true",
58 73 help="print a test coverage report inc. standard libraries")
59 74 parser.add_option("-t", "--timeout", type="int",
60 75 help="kill errant tests after TIMEOUT seconds"
61 76 " (default: $%s or %d)" % defaults['timeout'])
62 77 parser.add_option("--tmpdir", type="string",
63 78 help="run tests in the given temporary directory")
64 79 parser.add_option("-v", "--verbose", action="store_true",
65 80 help="output verbose messages")
66 81 parser.add_option("-n", "--nodiff", action="store_true",
67 82 help="skip showing test changes")
68 83 parser.add_option("--with-hg", type="string",
69 84 help="test existing install at given location")
70 85 parser.add_option("--pure", action="store_true",
71 86 help="use pure Python code instead of C extensions")
72 87
73 88 for option, default in defaults.items():
74 89 defaults[option] = int(os.environ.get(*default))
75 90 parser.set_defaults(**defaults)
76 91 (options, args) = parser.parse_args()
77 92 verbose = options.verbose
78 93 nodiff = options.nodiff
79 94 coverage = options.cover or options.cover_stdlib or options.annotate
80 95 python = sys.executable
81 96
82 97 if options.jobs < 1:
83 98 print >> sys.stderr, 'ERROR: -j/--jobs must be positive'
84 99 sys.exit(1)
85 100 if options.interactive and options.jobs > 1:
86 101 print '(--interactive overrides --jobs)'
87 102 options.jobs = 1
88 103
89 104 def rename(src, dst):
90 105 """Like os.rename(), trade atomicity and opened files friendliness
91 106 for existing destination support.
92 107 """
93 108 shutil.copy(src, dst)
94 109 os.remove(src)
95 110
96 111 def vlog(*msg):
97 112 if verbose:
98 113 for m in msg:
99 114 print m,
100 115 print
101 116
102 117 def splitnewlines(text):
103 118 '''like str.splitlines, but only split on newlines.
104 119 keep line endings.'''
105 120 i = 0
106 121 lines = []
107 122 while True:
108 123 n = text.find('\n', i)
109 124 if n == -1:
110 125 last = text[i:]
111 126 if last:
112 127 lines.append(last)
113 128 return lines
114 129 lines.append(text[i:n+1])
115 130 i = n + 1
116 131
117 132 def extract_missing_features(lines):
118 133 '''Extract missing/unknown features log lines as a list'''
119 134 missing = []
120 135 for line in lines:
121 136 if not line.startswith(SKIPPED_PREFIX):
122 137 continue
123 138 line = line.splitlines()[0]
124 139 missing.append(line[len(SKIPPED_PREFIX):])
125 140
126 141 return missing
127 142
128 143 def show_diff(expected, output):
129 144 for line in difflib.unified_diff(expected, output,
130 145 "Expected output", "Test output"):
131 146 sys.stdout.write(line)
132 147
133 148 def find_program(program):
134 149 """Search PATH for a executable program"""
135 150 for p in os.environ.get('PATH', os.defpath).split(os.pathsep):
136 151 name = os.path.join(p, program)
137 152 if os.access(name, os.X_OK):
138 153 return name
139 154 return None
140 155
141 156 def check_required_tools():
142 157 # Before we go any further, check for pre-requisite tools
143 158 # stuff from coreutils (cat, rm, etc) are not tested
144 159 for p in required_tools:
145 160 if os.name == 'nt':
146 161 p += '.exe'
147 162 found = find_program(p)
148 163 if found:
149 164 vlog("# Found prerequisite", p, "at", found)
150 165 else:
151 166 print "WARNING: Did not find prerequisite tool: "+p
152 167
153 168 def cleanup_exit():
154 169 if not options.keep_tmpdir:
155 170 if verbose:
156 171 print "# Cleaning up HGTMP", HGTMP
157 172 shutil.rmtree(HGTMP, True)
158 173
159 174 def use_correct_python():
160 175 # some tests run python interpreter. they must use same
161 176 # interpreter we use or bad things will happen.
162 177 exedir, exename = os.path.split(sys.executable)
163 178 if exename == 'python':
164 179 path = find_program('python')
165 180 if os.path.dirname(path) == exedir:
166 181 return
167 182 vlog('# Making python executable in test path use correct Python')
168 183 my_python = os.path.join(BINDIR, 'python')
169 184 try:
170 185 os.symlink(sys.executable, my_python)
171 186 except AttributeError:
172 187 # windows fallback
173 188 shutil.copyfile(sys.executable, my_python)
174 189 shutil.copymode(sys.executable, my_python)
175 190
176 191 def install_hg():
177 192 global python
178 193 vlog("# Performing temporary installation of HG")
179 194 installerrs = os.path.join("tests", "install.err")
180 195 pure = options.pure and "--pure" or ""
181 196
182 197 # Run installer in hg root
183 198 os.chdir(os.path.join(os.path.dirname(sys.argv[0]), '..'))
184 199 cmd = ('%s setup.py %s clean --all'
185 200 ' install --force --prefix="%s" --install-lib="%s"'
186 201 ' --install-scripts="%s" >%s 2>&1'
187 202 % (sys.executable, pure, INST, PYTHONDIR, BINDIR, installerrs))
188 203 vlog("# Running", cmd)
189 204 if os.system(cmd) == 0:
190 205 if not verbose:
191 206 os.remove(installerrs)
192 207 else:
193 208 f = open(installerrs)
194 209 for line in f:
195 210 print line,
196 211 f.close()
197 212 sys.exit(1)
198 213 os.chdir(TESTDIR)
199 214
200 215 os.environ["PATH"] = "%s%s%s" % (BINDIR, os.pathsep, os.environ["PATH"])
201 216
202 217 pydir = os.pathsep.join([PYTHONDIR, TESTDIR])
203 218 pythonpath = os.environ.get("PYTHONPATH")
204 219 if pythonpath:
205 220 pythonpath = pydir + os.pathsep + pythonpath
206 221 else:
207 222 pythonpath = pydir
208 223 os.environ["PYTHONPATH"] = pythonpath
209 224
210 225 use_correct_python()
211 226 global hgpkg
212 227 hgpkg = _hgpath()
213 228
214 229 vlog("# Installing dummy diffstat")
215 230 f = open(os.path.join(BINDIR, 'diffstat'), 'w')
216 231 f.write('#!' + sys.executable + '\n'
217 232 'import sys\n'
218 233 'files = 0\n'
219 234 'for line in sys.stdin:\n'
220 235 ' if line.startswith("diff "):\n'
221 236 ' files += 1\n'
222 237 'sys.stdout.write("files patched: %d\\n" % files)\n')
223 238 f.close()
224 239 os.chmod(os.path.join(BINDIR, 'diffstat'), 0700)
225 240
226 241 if coverage:
227 242 vlog("# Installing coverage wrapper")
228 243 os.environ['COVERAGE_FILE'] = COVERAGE_FILE
229 244 if os.path.exists(COVERAGE_FILE):
230 245 os.unlink(COVERAGE_FILE)
231 246 # Create a wrapper script to invoke hg via coverage.py
232 247 os.rename(os.path.join(BINDIR, "hg"), os.path.join(BINDIR, "_hg.py"))
233 248 f = open(os.path.join(BINDIR, 'hg'), 'w')
234 249 f.write('#!' + sys.executable + '\n')
235 250 f.write('import sys, os; os.execv(sys.executable, [sys.executable, '
236 251 '"%s", "-x", "%s"] + sys.argv[1:])\n' %
237 252 (os.path.join(TESTDIR, 'coverage.py'),
238 253 os.path.join(BINDIR, '_hg.py')))
239 254 f.close()
240 255 os.chmod(os.path.join(BINDIR, 'hg'), 0700)
241 256 python = '"%s" "%s" -x' % (sys.executable,
242 257 os.path.join(TESTDIR,'coverage.py'))
243 258
244 259 def output_coverage():
245 260 vlog("# Producing coverage report")
246 261 omit = [BINDIR, TESTDIR, PYTHONDIR]
247 262 if not options.cover_stdlib:
248 263 # Exclude as system paths (ignoring empty strings seen on win)
249 264 omit += [x for x in sys.path if x != '']
250 265 omit = ','.join(omit)
251 266 os.chdir(PYTHONDIR)
252 267 cmd = '"%s" "%s" -i -r "--omit=%s"' % (
253 268 sys.executable, os.path.join(TESTDIR, 'coverage.py'), omit)
254 269 vlog("# Running: "+cmd)
255 270 os.system(cmd)
256 271 if options.annotate:
257 272 adir = os.path.join(TESTDIR, 'annotated')
258 273 if not os.path.isdir(adir):
259 274 os.mkdir(adir)
260 275 cmd = '"%s" "%s" -i -a "--directory=%s" "--omit=%s"' % (
261 276 sys.executable, os.path.join(TESTDIR, 'coverage.py'),
262 277 adir, omit)
263 278 vlog("# Running: "+cmd)
264 279 os.system(cmd)
265 280
266 281 class Timeout(Exception):
267 282 pass
268 283
269 284 def alarmed(signum, frame):
270 285 raise Timeout
271 286
272 287 def run(cmd):
273 288 """Run command in a sub-process, capturing the output (stdout and stderr).
274 289 Return the exist code, and output."""
275 290 # TODO: Use subprocess.Popen if we're running on Python 2.4
276 291 if os.name == 'nt' or sys.platform.startswith('java'):
277 292 tochild, fromchild = os.popen4(cmd)
278 293 tochild.close()
279 294 output = fromchild.read()
280 295 ret = fromchild.close()
281 296 if ret == None:
282 297 ret = 0
283 298 else:
284 proc = popen2.Popen4(cmd)
299 proc = Popen4(cmd)
285 300 try:
286 301 output = ''
287 302 proc.tochild.close()
288 303 output = proc.fromchild.read()
289 304 ret = proc.wait()
290 305 if os.WIFEXITED(ret):
291 306 ret = os.WEXITSTATUS(ret)
292 307 except Timeout:
293 308 vlog('# Process %d timed out - killing it' % proc.pid)
294 309 os.kill(proc.pid, signal.SIGTERM)
295 310 ret = proc.wait()
296 311 if ret == 0:
297 312 ret = signal.SIGTERM << 8
298 313 output += ("\n### Abort: timeout after %d seconds.\n"
299 314 % options.timeout)
300 315 return ret, splitnewlines(output)
301 316
302 317 def run_one(test, skips, fails):
303 318 '''tristate output:
304 319 None -> skipped
305 320 True -> passed
306 321 False -> failed'''
307 322
308 323 def skip(msg):
309 324 if not verbose:
310 325 skips.append((test, msg))
311 326 else:
312 327 print "\nSkipping %s: %s" % (test, msg)
313 328 return None
314 329
315 330 def fail(msg):
316 331 fails.append((test, msg))
317 332 if not nodiff:
318 333 print "\nERROR: %s %s" % (test, msg)
319 334 return None
320 335
321 336 vlog("# Test", test)
322 337
323 338 # create a fresh hgrc
324 339 hgrc = file(HGRCPATH, 'w+')
325 340 hgrc.write('[ui]\n')
326 341 hgrc.write('slash = True\n')
327 342 hgrc.write('[defaults]\n')
328 343 hgrc.write('backout = -d "0 0"\n')
329 344 hgrc.write('commit = -d "0 0"\n')
330 345 hgrc.write('debugrawcommit = -d "0 0"\n')
331 346 hgrc.write('tag = -d "0 0"\n')
332 347 hgrc.close()
333 348
334 349 err = os.path.join(TESTDIR, test+".err")
335 350 ref = os.path.join(TESTDIR, test+".out")
336 351 testpath = os.path.join(TESTDIR, test)
337 352
338 353 if os.path.exists(err):
339 354 os.remove(err) # Remove any previous output files
340 355
341 356 # Make a tmp subdirectory to work in
342 357 tmpd = os.path.join(HGTMP, test)
343 358 os.mkdir(tmpd)
344 359 os.chdir(tmpd)
345 360
346 361 try:
347 362 tf = open(testpath)
348 363 firstline = tf.readline().rstrip()
349 364 tf.close()
350 365 except:
351 366 firstline = ''
352 367 lctest = test.lower()
353 368
354 369 if lctest.endswith('.py') or firstline == '#!/usr/bin/env python':
355 370 cmd = '%s "%s"' % (python, testpath)
356 371 elif lctest.endswith('.bat'):
357 372 # do not run batch scripts on non-windows
358 373 if os.name != 'nt':
359 374 return skip("batch script")
360 375 # To reliably get the error code from batch files on WinXP,
361 376 # the "cmd /c call" prefix is needed. Grrr
362 377 cmd = 'cmd /c call "%s"' % testpath
363 378 else:
364 379 # do not run shell scripts on windows
365 380 if os.name == 'nt':
366 381 return skip("shell script")
367 382 # do not try to run non-executable programs
368 383 if not os.path.exists(testpath):
369 384 return fail("does not exist")
370 385 elif not os.access(testpath, os.X_OK):
371 386 return skip("not executable")
372 387 cmd = '"%s"' % testpath
373 388
374 389 if options.timeout > 0:
375 390 signal.alarm(options.timeout)
376 391
377 392 vlog("# Running", cmd)
378 393 ret, out = run(cmd)
379 394 vlog("# Ret was:", ret)
380 395
381 396 if options.timeout > 0:
382 397 signal.alarm(0)
383 398
384 399 mark = '.'
385 400
386 401 skipped = (ret == SKIPPED_STATUS)
387 402 # If reference output file exists, check test output against it
388 403 if os.path.exists(ref):
389 404 f = open(ref, "r")
390 405 ref_out = splitnewlines(f.read())
391 406 f.close()
392 407 else:
393 408 ref_out = []
394 409 if skipped:
395 410 mark = 's'
396 411 missing = extract_missing_features(out)
397 412 if not missing:
398 413 missing = ['irrelevant']
399 414 skip(missing[-1])
400 415 elif out != ref_out:
401 416 mark = '!'
402 417 if ret:
403 418 fail("output changed and returned error code %d" % ret)
404 419 else:
405 420 fail("output changed")
406 421 if not nodiff:
407 422 show_diff(ref_out, out)
408 423 ret = 1
409 424 elif ret:
410 425 mark = '!'
411 426 fail("returned error code %d" % ret)
412 427
413 428 if not verbose:
414 429 sys.stdout.write(mark)
415 430 sys.stdout.flush()
416 431
417 432 if ret != 0 and not skipped:
418 433 # Save errors to a file for diagnosis
419 434 f = open(err, "wb")
420 435 for line in out:
421 436 f.write(line)
422 437 f.close()
423 438
424 439 # Kill off any leftover daemon processes
425 440 try:
426 441 fp = file(DAEMON_PIDS)
427 442 for line in fp:
428 443 try:
429 444 pid = int(line)
430 445 except ValueError:
431 446 continue
432 447 try:
433 448 os.kill(pid, 0)
434 449 vlog('# Killing daemon process %d' % pid)
435 450 os.kill(pid, signal.SIGTERM)
436 451 time.sleep(0.25)
437 452 os.kill(pid, 0)
438 453 vlog('# Daemon process %d is stuck - really killing it' % pid)
439 454 os.kill(pid, signal.SIGKILL)
440 455 except OSError, err:
441 456 if err.errno != errno.ESRCH:
442 457 raise
443 458 fp.close()
444 459 os.unlink(DAEMON_PIDS)
445 460 except IOError:
446 461 pass
447 462
448 463 os.chdir(TESTDIR)
449 464 if not options.keep_tmpdir:
450 465 shutil.rmtree(tmpd, True)
451 466 if skipped:
452 467 return None
453 468 return ret == 0
454 469
455 470 if not options.child:
456 471 os.umask(022)
457 472
458 473 check_required_tools()
459 474
460 475 # Reset some environment variables to well-known values so that
461 476 # the tests produce repeatable output.
462 477 os.environ['LANG'] = os.environ['LC_ALL'] = 'C'
463 478 os.environ['TZ'] = 'GMT'
464 479 os.environ["EMAIL"] = "Foo Bar <foo.bar@example.com>"
465 480 os.environ['CDPATH'] = ''
466 481
467 482 TESTDIR = os.environ["TESTDIR"] = os.getcwd()
468 483 HGTMP = os.environ['HGTMP'] = os.path.realpath(tempfile.mkdtemp('', 'hgtests.',
469 484 options.tmpdir))
470 485 DAEMON_PIDS = None
471 486 HGRCPATH = None
472 487
473 488 os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
474 489 os.environ["HGMERGE"] = "internal:merge"
475 490 os.environ["HGUSER"] = "test"
476 491 os.environ["HGENCODING"] = "ascii"
477 492 os.environ["HGENCODINGMODE"] = "strict"
478 493 os.environ["HGPORT"] = str(options.port)
479 494 os.environ["HGPORT1"] = str(options.port + 1)
480 495 os.environ["HGPORT2"] = str(options.port + 2)
481 496
482 497 if options.with_hg:
483 498 INST = options.with_hg
484 499 else:
485 500 INST = os.path.join(HGTMP, "install")
486 501 BINDIR = os.environ["BINDIR"] = os.path.join(INST, "bin")
487 502 PYTHONDIR = os.path.join(INST, "lib", "python")
488 503 COVERAGE_FILE = os.path.join(TESTDIR, ".coverage")
489 504
490 505 def _hgpath():
491 506 cmd = '%s -c "import mercurial; print mercurial.__path__[0]"'
492 507 hgpath = os.popen(cmd % python)
493 508 path = hgpath.read().strip()
494 509 hgpath.close()
495 510 return path
496 511
497 512 expecthg = os.path.join(HGTMP, 'install', 'lib', 'python', 'mercurial')
498 513 hgpkg = None
499 514
500 515 def run_children(tests):
501 516 if not options.with_hg:
502 517 install_hg()
503 518 if hgpkg != expecthg:
504 519 print '# Testing unexpected mercurial: %s' % hgpkg
505 520
506 521 optcopy = dict(options.__dict__)
507 522 optcopy['jobs'] = 1
508 523 optcopy['with_hg'] = INST
509 524 opts = []
510 525 for opt, value in optcopy.iteritems():
511 526 name = '--' + opt.replace('_', '-')
512 527 if value is True:
513 528 opts.append(name)
514 529 elif value is not None:
515 530 opts.append(name + '=' + str(value))
516 531
517 532 tests.reverse()
518 533 jobs = [[] for j in xrange(options.jobs)]
519 534 while tests:
520 535 for j in xrange(options.jobs):
521 536 if not tests: break
522 537 jobs[j].append(tests.pop())
523 538 fps = {}
524 539 for j in xrange(len(jobs)):
525 540 job = jobs[j]
526 541 if not job:
527 542 continue
528 543 rfd, wfd = os.pipe()
529 544 childopts = ['--child=%d' % wfd, '--port=%d' % (options.port + j * 3)]
530 545 cmdline = [python, sys.argv[0]] + opts + childopts + job
531 546 vlog(' '.join(cmdline))
532 547 fps[os.spawnvp(os.P_NOWAIT, cmdline[0], cmdline)] = os.fdopen(rfd, 'r')
533 548 os.close(wfd)
534 549 failures = 0
535 550 tested, skipped, failed = 0, 0, 0
536 551 skips = []
537 552 fails = []
538 553 while fps:
539 554 pid, status = os.wait()
540 555 fp = fps.pop(pid)
541 556 l = fp.read().splitlines()
542 557 test, skip, fail = map(int, l[:3])
543 558 split = -fail or len(l)
544 559 for s in l[3:split]:
545 560 skips.append(s.split(" ", 1))
546 561 for s in l[split:]:
547 562 fails.append(s.split(" ", 1))
548 563 tested += test
549 564 skipped += skip
550 565 failed += fail
551 566 vlog('pid %d exited, status %d' % (pid, status))
552 567 failures |= status
553 568 print
554 569 for s in skips:
555 570 print "Skipped %s: %s" % (s[0], s[1])
556 571 for s in fails:
557 572 print "Failed %s: %s" % (s[0], s[1])
558 573
559 574 if hgpkg != expecthg:
560 575 print '# Tested unexpected mercurial: %s' % hgpkg
561 576 print "# Ran %d tests, %d skipped, %d failed." % (
562 577 tested, skipped, failed)
563 578 sys.exit(failures != 0)
564 579
565 580 def run_tests(tests):
566 581 global DAEMON_PIDS, HGRCPATH
567 582 DAEMON_PIDS = os.environ["DAEMON_PIDS"] = os.path.join(HGTMP, 'daemon.pids')
568 583 HGRCPATH = os.environ["HGRCPATH"] = os.path.join(HGTMP, '.hgrc')
569 584
570 585 try:
571 586 if not options.with_hg:
572 587 install_hg()
573 588
574 589 if hgpkg != expecthg:
575 590 print '# Testing unexpected mercurial: %s' % hgpkg
576 591
577 592 if options.timeout > 0:
578 593 try:
579 594 signal.signal(signal.SIGALRM, alarmed)
580 595 vlog('# Running tests with %d-second timeout' %
581 596 options.timeout)
582 597 except AttributeError:
583 598 print 'WARNING: cannot run tests with timeouts'
584 599 options.timeout = 0
585 600
586 601 tested = 0
587 602 failed = 0
588 603 skipped = 0
589 604
590 605 if options.restart:
591 606 orig = list(tests)
592 607 while tests:
593 608 if os.path.exists(tests[0] + ".err"):
594 609 break
595 610 tests.pop(0)
596 611 if not tests:
597 612 print "running all tests"
598 613 tests = orig
599 614
600 615 skips = []
601 616 fails = []
602 617 for test in tests:
603 618 if options.retest and not os.path.exists(test + ".err"):
604 619 skipped += 1
605 620 continue
606 621 ret = run_one(test, skips, fails)
607 622 if ret is None:
608 623 skipped += 1
609 624 elif not ret:
610 625 if options.interactive:
611 626 print "Accept this change? [n] ",
612 627 answer = sys.stdin.readline().strip()
613 628 if answer.lower() in "y yes".split():
614 629 rename(test + ".err", test + ".out")
615 630 tested += 1
616 631 fails.pop()
617 632 continue
618 633 failed += 1
619 634 if options.first:
620 635 break
621 636 tested += 1
622 637
623 638 if options.child:
624 639 fp = os.fdopen(options.child, 'w')
625 640 fp.write('%d\n%d\n%d\n' % (tested, skipped, failed))
626 641 for s in skips:
627 642 fp.write("%s %s\n" % s)
628 643 for s in fails:
629 644 fp.write("%s %s\n" % s)
630 645 fp.close()
631 646 else:
632 647 print
633 648 for s in skips:
634 649 print "Skipped %s: %s" % s
635 650 for s in fails:
636 651 print "Failed %s: %s" % s
637 652 if hgpkg != expecthg:
638 653 print '# Tested unexpected mercurial: %s' % hgpkg
639 654 print "# Ran %d tests, %d skipped, %d failed." % (
640 655 tested, skipped, failed)
641 656
642 657 if coverage:
643 658 output_coverage()
644 659 except KeyboardInterrupt:
645 660 failed = True
646 661 print "\ninterrupted!"
647 662
648 663 if failed:
649 664 sys.exit(1)
650 665
651 666 if len(args) == 0:
652 667 args = os.listdir(".")
653 668 args.sort()
654 669
655 670 tests = []
656 671 for test in args:
657 672 if (test.startswith("test-") and '~' not in test and
658 673 ('.' not in test or test.endswith('.py') or
659 674 test.endswith('.bat'))):
660 675 tests.append(test)
661 676
662 677 vlog("# Using TESTDIR", TESTDIR)
663 678 vlog("# Using HGTMP", HGTMP)
664 679
665 680 try:
666 681 if len(tests) > 1 and options.jobs > 1:
667 682 run_children(tests)
668 683 else:
669 684 run_tests(tests)
670 685 finally:
671 686 cleanup_exit()
General Comments 0
You need to be logged in to leave comments. Login now