##// END OF EJS Templates
run-tests: factor out main(); reduce use of globals a bit.
Greg Ward -
r8094:60a9e3cf default
parent child Browse files
Show More
@@ -1,709 +1,713 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 def cleanup_exit():
186 def cleanup_exit(options):
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 def install_hg():
209 def install_hg(options):
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 277 def _hgpath():
278 278 cmd = '%s -c "import mercurial; print mercurial.__path__[0]"'
279 279 hgpath = os.popen(cmd % python)
280 280 path = hgpath.read().strip()
281 281 hgpath.close()
282 282 return path
283 283
284 def output_coverage():
284 def output_coverage(options):
285 285 vlog("# Producing coverage report")
286 286 omit = [BINDIR, TESTDIR, PYTHONDIR]
287 287 if not options.cover_stdlib:
288 288 # Exclude as system paths (ignoring empty strings seen on win)
289 289 omit += [x for x in sys.path if x != '']
290 290 omit = ','.join(omit)
291 291 os.chdir(PYTHONDIR)
292 292 cmd = '"%s" "%s" -i -r "--omit=%s"' % (
293 293 sys.executable, os.path.join(TESTDIR, 'coverage.py'), omit)
294 294 vlog("# Running: "+cmd)
295 295 os.system(cmd)
296 296 if options.annotate:
297 297 adir = os.path.join(TESTDIR, 'annotated')
298 298 if not os.path.isdir(adir):
299 299 os.mkdir(adir)
300 300 cmd = '"%s" "%s" -i -a "--directory=%s" "--omit=%s"' % (
301 301 sys.executable, os.path.join(TESTDIR, 'coverage.py'),
302 302 adir, omit)
303 303 vlog("# Running: "+cmd)
304 304 os.system(cmd)
305 305
306 306 class Timeout(Exception):
307 307 pass
308 308
309 309 def alarmed(signum, frame):
310 310 raise Timeout
311 311
312 312 def run(cmd):
313 313 """Run command in a sub-process, capturing the output (stdout and stderr).
314 314 Return the exist code, and output."""
315 315 # TODO: Use subprocess.Popen if we're running on Python 2.4
316 316 if os.name == 'nt' or sys.platform.startswith('java'):
317 317 tochild, fromchild = os.popen4(cmd)
318 318 tochild.close()
319 319 output = fromchild.read()
320 320 ret = fromchild.close()
321 321 if ret == None:
322 322 ret = 0
323 323 else:
324 324 proc = Popen4(cmd)
325 325 try:
326 326 output = ''
327 327 proc.tochild.close()
328 328 output = proc.fromchild.read()
329 329 ret = proc.wait()
330 330 if os.WIFEXITED(ret):
331 331 ret = os.WEXITSTATUS(ret)
332 332 except Timeout:
333 333 vlog('# Process %d timed out - killing it' % proc.pid)
334 334 os.kill(proc.pid, signal.SIGTERM)
335 335 ret = proc.wait()
336 336 if ret == 0:
337 337 ret = signal.SIGTERM << 8
338 338 output += ("\n### Abort: timeout after %d seconds.\n"
339 339 % options.timeout)
340 340 return ret, splitnewlines(output)
341 341
342 def run_one(test, skips, fails):
342 def run_one(options, test, skips, fails):
343 343 '''tristate output:
344 344 None -> skipped
345 345 True -> passed
346 346 False -> failed'''
347 347
348 348 def skip(msg):
349 349 if not verbose:
350 350 skips.append((test, msg))
351 351 else:
352 352 print "\nSkipping %s: %s" % (test, msg)
353 353 return None
354 354
355 355 def fail(msg):
356 356 fails.append((test, msg))
357 357 if not nodiff:
358 358 print "\nERROR: %s %s" % (test, msg)
359 359 return None
360 360
361 361 vlog("# Test", test)
362 362
363 363 # create a fresh hgrc
364 364 hgrc = file(HGRCPATH, 'w+')
365 365 hgrc.write('[ui]\n')
366 366 hgrc.write('slash = True\n')
367 367 hgrc.write('[defaults]\n')
368 368 hgrc.write('backout = -d "0 0"\n')
369 369 hgrc.write('commit = -d "0 0"\n')
370 370 hgrc.write('debugrawcommit = -d "0 0"\n')
371 371 hgrc.write('tag = -d "0 0"\n')
372 372 hgrc.close()
373 373
374 374 err = os.path.join(TESTDIR, test+".err")
375 375 ref = os.path.join(TESTDIR, test+".out")
376 376 testpath = os.path.join(TESTDIR, test)
377 377
378 378 if os.path.exists(err):
379 379 os.remove(err) # Remove any previous output files
380 380
381 381 # Make a tmp subdirectory to work in
382 382 tmpd = os.path.join(HGTMP, test)
383 383 os.mkdir(tmpd)
384 384 os.chdir(tmpd)
385 385
386 386 try:
387 387 tf = open(testpath)
388 388 firstline = tf.readline().rstrip()
389 389 tf.close()
390 390 except:
391 391 firstline = ''
392 392 lctest = test.lower()
393 393
394 394 if lctest.endswith('.py') or firstline == '#!/usr/bin/env python':
395 395 cmd = '%s "%s"' % (python, testpath)
396 396 elif lctest.endswith('.bat'):
397 397 # do not run batch scripts on non-windows
398 398 if os.name != 'nt':
399 399 return skip("batch script")
400 400 # To reliably get the error code from batch files on WinXP,
401 401 # the "cmd /c call" prefix is needed. Grrr
402 402 cmd = 'cmd /c call "%s"' % testpath
403 403 else:
404 404 # do not run shell scripts on windows
405 405 if os.name == 'nt':
406 406 return skip("shell script")
407 407 # do not try to run non-executable programs
408 408 if not os.path.exists(testpath):
409 409 return fail("does not exist")
410 410 elif not os.access(testpath, os.X_OK):
411 411 return skip("not executable")
412 412 cmd = '"%s"' % testpath
413 413
414 414 if options.timeout > 0:
415 415 signal.alarm(options.timeout)
416 416
417 417 vlog("# Running", cmd)
418 418 ret, out = run(cmd)
419 419 vlog("# Ret was:", ret)
420 420
421 421 if options.timeout > 0:
422 422 signal.alarm(0)
423 423
424 424 mark = '.'
425 425
426 426 skipped = (ret == SKIPPED_STATUS)
427 427 # If reference output file exists, check test output against it
428 428 if os.path.exists(ref):
429 429 f = open(ref, "r")
430 430 ref_out = splitnewlines(f.read())
431 431 f.close()
432 432 else:
433 433 ref_out = []
434 434 if skipped:
435 435 mark = 's'
436 436 missing, failed = parse_hghave_output(out)
437 437 if not missing:
438 438 missing = ['irrelevant']
439 439 if failed:
440 440 fail("hghave failed checking for %s" % failed[-1])
441 441 skipped = False
442 442 else:
443 443 skip(missing[-1])
444 444 elif out != ref_out:
445 445 mark = '!'
446 446 if ret:
447 447 fail("output changed and returned error code %d" % ret)
448 448 else:
449 449 fail("output changed")
450 450 if not nodiff:
451 451 show_diff(ref_out, out)
452 452 ret = 1
453 453 elif ret:
454 454 mark = '!'
455 455 fail("returned error code %d" % ret)
456 456
457 457 if not verbose:
458 458 sys.stdout.write(mark)
459 459 sys.stdout.flush()
460 460
461 461 if ret != 0 and not skipped:
462 462 # Save errors to a file for diagnosis
463 463 f = open(err, "wb")
464 464 for line in out:
465 465 f.write(line)
466 466 f.close()
467 467
468 468 # Kill off any leftover daemon processes
469 469 try:
470 470 fp = file(DAEMON_PIDS)
471 471 for line in fp:
472 472 try:
473 473 pid = int(line)
474 474 except ValueError:
475 475 continue
476 476 try:
477 477 os.kill(pid, 0)
478 478 vlog('# Killing daemon process %d' % pid)
479 479 os.kill(pid, signal.SIGTERM)
480 480 time.sleep(0.25)
481 481 os.kill(pid, 0)
482 482 vlog('# Daemon process %d is stuck - really killing it' % pid)
483 483 os.kill(pid, signal.SIGKILL)
484 484 except OSError, err:
485 485 if err.errno != errno.ESRCH:
486 486 raise
487 487 fp.close()
488 488 os.unlink(DAEMON_PIDS)
489 489 except IOError:
490 490 pass
491 491
492 492 os.chdir(TESTDIR)
493 493 if not options.keep_tmpdir:
494 494 shutil.rmtree(tmpd, True)
495 495 if skipped:
496 496 return None
497 497 return ret == 0
498 498
499 def run_children(tests):
499 def run_children(options, expecthg, tests):
500 500 if not options.with_hg:
501 501 install_hg()
502 502 if hgpkg != expecthg:
503 503 print '# Testing unexpected mercurial: %s' % hgpkg
504 504
505 505 optcopy = dict(options.__dict__)
506 506 optcopy['jobs'] = 1
507 507 optcopy['with_hg'] = INST
508 508 opts = []
509 509 for opt, value in optcopy.iteritems():
510 510 name = '--' + opt.replace('_', '-')
511 511 if value is True:
512 512 opts.append(name)
513 513 elif value is not None:
514 514 opts.append(name + '=' + str(value))
515 515
516 516 tests.reverse()
517 517 jobs = [[] for j in xrange(options.jobs)]
518 518 while tests:
519 519 for j in xrange(options.jobs):
520 520 if not tests: break
521 521 jobs[j].append(tests.pop())
522 522 fps = {}
523 523 for j in xrange(len(jobs)):
524 524 job = jobs[j]
525 525 if not job:
526 526 continue
527 527 rfd, wfd = os.pipe()
528 528 childopts = ['--child=%d' % wfd, '--port=%d' % (options.port + j * 3)]
529 529 cmdline = [python, sys.argv[0]] + opts + childopts + job
530 530 vlog(' '.join(cmdline))
531 531 fps[os.spawnvp(os.P_NOWAIT, cmdline[0], cmdline)] = os.fdopen(rfd, 'r')
532 532 os.close(wfd)
533 533 failures = 0
534 534 tested, skipped, failed = 0, 0, 0
535 535 skips = []
536 536 fails = []
537 537 while fps:
538 538 pid, status = os.wait()
539 539 fp = fps.pop(pid)
540 540 l = fp.read().splitlines()
541 541 test, skip, fail = map(int, l[:3])
542 542 split = -fail or len(l)
543 543 for s in l[3:split]:
544 544 skips.append(s.split(" ", 1))
545 545 for s in l[split:]:
546 546 fails.append(s.split(" ", 1))
547 547 tested += test
548 548 skipped += skip
549 549 failed += fail
550 550 vlog('pid %d exited, status %d' % (pid, status))
551 551 failures |= status
552 552 print
553 553 for s in skips:
554 554 print "Skipped %s: %s" % (s[0], s[1])
555 555 for s in fails:
556 556 print "Failed %s: %s" % (s[0], s[1])
557 557
558 558 if hgpkg != expecthg:
559 559 print '# Tested unexpected mercurial: %s' % hgpkg
560 560 print "# Ran %d tests, %d skipped, %d failed." % (
561 561 tested, skipped, failed)
562 562 sys.exit(failures != 0)
563 563
564 def run_tests(tests):
564 def run_tests(options, expecthg, tests):
565 565 global DAEMON_PIDS, HGRCPATH
566 566 DAEMON_PIDS = os.environ["DAEMON_PIDS"] = os.path.join(HGTMP, 'daemon.pids')
567 567 HGRCPATH = os.environ["HGRCPATH"] = os.path.join(HGTMP, '.hgrc')
568 568
569 569 try:
570 570 if not options.with_hg:
571 install_hg()
571 install_hg(options)
572 572
573 573 if hgpkg != expecthg:
574 574 print '# Testing unexpected mercurial: %s' % hgpkg
575 575
576 576 if options.timeout > 0:
577 577 try:
578 578 signal.signal(signal.SIGALRM, alarmed)
579 579 vlog('# Running tests with %d-second timeout' %
580 580 options.timeout)
581 581 except AttributeError:
582 582 print 'WARNING: cannot run tests with timeouts'
583 583 options.timeout = 0
584 584
585 585 tested = 0
586 586 failed = 0
587 587 skipped = 0
588 588
589 589 if options.restart:
590 590 orig = list(tests)
591 591 while tests:
592 592 if os.path.exists(tests[0] + ".err"):
593 593 break
594 594 tests.pop(0)
595 595 if not tests:
596 596 print "running all tests"
597 597 tests = orig
598 598
599 599 skips = []
600 600 fails = []
601 601 for test in tests:
602 602 if options.retest and not os.path.exists(test + ".err"):
603 603 skipped += 1
604 604 continue
605 ret = run_one(test, skips, fails)
605 ret = run_one(options, test, skips, fails)
606 606 if ret is None:
607 607 skipped += 1
608 608 elif not ret:
609 609 if options.interactive:
610 610 print "Accept this change? [n] ",
611 611 answer = sys.stdin.readline().strip()
612 612 if answer.lower() in "y yes".split():
613 613 rename(test + ".err", test + ".out")
614 614 tested += 1
615 615 fails.pop()
616 616 continue
617 617 failed += 1
618 618 if options.first:
619 619 break
620 620 tested += 1
621 621
622 622 if options.child:
623 623 fp = os.fdopen(options.child, 'w')
624 624 fp.write('%d\n%d\n%d\n' % (tested, skipped, failed))
625 625 for s in skips:
626 626 fp.write("%s %s\n" % s)
627 627 for s in fails:
628 628 fp.write("%s %s\n" % s)
629 629 fp.close()
630 630 else:
631 631 print
632 632 for s in skips:
633 633 print "Skipped %s: %s" % s
634 634 for s in fails:
635 635 print "Failed %s: %s" % s
636 636 if hgpkg != expecthg:
637 637 print '# Tested unexpected mercurial: %s' % hgpkg
638 638 print "# Ran %d tests, %d skipped, %d failed." % (
639 639 tested, skipped, failed)
640 640
641 641 if coverage:
642 output_coverage()
642 output_coverage(options)
643 643 except KeyboardInterrupt:
644 644 failed = True
645 645 print "\ninterrupted!"
646 646
647 647 if failed:
648 648 sys.exit(1)
649 649
650 (options, args) = parse_args()
651 if not options.child:
652 os.umask(022)
650 def main():
651 (options, args) = parse_args()
652 if not options.child:
653 os.umask(022)
653 654
654 check_required_tools()
655 check_required_tools()
655 656
656 # Reset some environment variables to well-known values so that
657 # the tests produce repeatable output.
658 os.environ['LANG'] = os.environ['LC_ALL'] = 'C'
659 os.environ['TZ'] = 'GMT'
660 os.environ["EMAIL"] = "Foo Bar <foo.bar@example.com>"
661 os.environ['CDPATH'] = ''
657 # Reset some environment variables to well-known values so that
658 # the tests produce repeatable output.
659 os.environ['LANG'] = os.environ['LC_ALL'] = 'C'
660 os.environ['TZ'] = 'GMT'
661 os.environ["EMAIL"] = "Foo Bar <foo.bar@example.com>"
662 os.environ['CDPATH'] = ''
662 663
663 TESTDIR = os.environ["TESTDIR"] = os.getcwd()
664 HGTMP = os.environ['HGTMP'] = os.path.realpath(tempfile.mkdtemp('', 'hgtests.',
665 options.tmpdir))
666 DAEMON_PIDS = None
667 HGRCPATH = None
664 global TESTDIR, HGTMP, INST, BINDIR, PYTHONDIR, COVERAGE_FILE
665 TESTDIR = os.environ["TESTDIR"] = os.getcwd()
666 HGTMP = os.environ['HGTMP'] = os.path.realpath(tempfile.mkdtemp('', 'hgtests.',
667 options.tmpdir))
668 DAEMON_PIDS = None
669 HGRCPATH = None
668 670
669 os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
670 os.environ["HGMERGE"] = "internal:merge"
671 os.environ["HGUSER"] = "test"
672 os.environ["HGENCODING"] = "ascii"
673 os.environ["HGENCODINGMODE"] = "strict"
674 os.environ["HGPORT"] = str(options.port)
675 os.environ["HGPORT1"] = str(options.port + 1)
676 os.environ["HGPORT2"] = str(options.port + 2)
671 os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
672 os.environ["HGMERGE"] = "internal:merge"
673 os.environ["HGUSER"] = "test"
674 os.environ["HGENCODING"] = "ascii"
675 os.environ["HGENCODINGMODE"] = "strict"
676 os.environ["HGPORT"] = str(options.port)
677 os.environ["HGPORT1"] = str(options.port + 1)
678 os.environ["HGPORT2"] = str(options.port + 2)
677 679
678 if options.with_hg:
679 INST = options.with_hg
680 else:
681 INST = os.path.join(HGTMP, "install")
682 BINDIR = os.environ["BINDIR"] = os.path.join(INST, "bin")
683 PYTHONDIR = os.path.join(INST, "lib", "python")
684 COVERAGE_FILE = os.path.join(TESTDIR, ".coverage")
680 if options.with_hg:
681 INST = options.with_hg
682 else:
683 INST = os.path.join(HGTMP, "install")
684 BINDIR = os.environ["BINDIR"] = os.path.join(INST, "bin")
685 PYTHONDIR = os.path.join(INST, "lib", "python")
686 COVERAGE_FILE = os.path.join(TESTDIR, ".coverage")
685 687
686 expecthg = os.path.join(HGTMP, 'install', 'lib', 'python', 'mercurial')
687 hgpkg = None
688 expecthg = os.path.join(HGTMP, 'install', 'lib', 'python', 'mercurial')
689 hgpkg = None
688 690
689 if len(args) == 0:
690 args = os.listdir(".")
691 args.sort()
691 if len(args) == 0:
692 args = os.listdir(".")
693 args.sort()
692 694
693 tests = []
694 for test in args:
695 if (test.startswith("test-") and '~' not in test and
696 ('.' not in test or test.endswith('.py') or
697 test.endswith('.bat'))):
698 tests.append(test)
695 tests = []
696 for test in args:
697 if (test.startswith("test-") and '~' not in test and
698 ('.' not in test or test.endswith('.py') or
699 test.endswith('.bat'))):
700 tests.append(test)
701
702 vlog("# Using TESTDIR", TESTDIR)
703 vlog("# Using HGTMP", HGTMP)
699 704
700 vlog("# Using TESTDIR", TESTDIR)
701 vlog("# Using HGTMP", HGTMP)
705 try:
706 if len(tests) > 1 and options.jobs > 1:
707 run_children(options, expecthg, tests)
708 else:
709 run_tests(options, expecthg, tests)
710 finally:
711 cleanup_exit(options)
702 712
703 try:
704 if len(tests) > 1 and options.jobs > 1:
705 run_children(tests)
706 else:
707 run_tests(tests)
708 finally:
709 cleanup_exit()
713 main()
General Comments 0
You need to be logged in to leave comments. Login now