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