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