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