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