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