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