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