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