##// END OF EJS Templates
run-tests: remove dead code for supporting old test scripts
Mads Kiilerich -
r17801:03554dfc default
parent child Browse files
Show More
@@ -1,1300 +1,1292 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 or any later version.
9 9
10 10 # Modifying this script is tricky because it has many modes:
11 11 # - serial (default) vs parallel (-jN, N > 1)
12 12 # - no coverage (default) vs coverage (-c, -C, -s)
13 13 # - temp install (default) vs specific hg script (--with-hg, --local)
14 14 # - tests are a mix of shell scripts and Python scripts
15 15 #
16 16 # If you change this script, it is recommended that you ensure you
17 17 # haven't broken it by running it in various modes with a representative
18 18 # sample of test scripts. For example:
19 19 #
20 20 # 1) serial, no coverage, temp install:
21 21 # ./run-tests.py test-s*
22 22 # 2) serial, no coverage, local hg:
23 23 # ./run-tests.py --local test-s*
24 24 # 3) serial, coverage, temp install:
25 25 # ./run-tests.py -c test-s*
26 26 # 4) serial, coverage, local hg:
27 27 # ./run-tests.py -c --local test-s* # unsupported
28 28 # 5) parallel, no coverage, temp install:
29 29 # ./run-tests.py -j2 test-s*
30 30 # 6) parallel, no coverage, local hg:
31 31 # ./run-tests.py -j2 --local test-s*
32 32 # 7) parallel, coverage, temp install:
33 33 # ./run-tests.py -j2 -c test-s* # currently broken
34 34 # 8) parallel, coverage, local install:
35 35 # ./run-tests.py -j2 -c --local test-s* # unsupported (and broken)
36 36 # 9) parallel, custom tmp dir:
37 37 # ./run-tests.py -j2 --tmpdir /tmp/myhgtests
38 38 #
39 39 # (You could use any subset of the tests: test-s* happens to match
40 40 # enough that it's worth doing parallel runs, few enough that it
41 41 # completes fairly quickly, includes both shell and Python scripts, and
42 42 # includes some scripts that run daemon processes.)
43 43
44 44 from distutils import version
45 45 import difflib
46 46 import errno
47 47 import optparse
48 48 import os
49 49 import shutil
50 50 import subprocess
51 51 import signal
52 52 import sys
53 53 import tempfile
54 54 import time
55 55 import re
56 56 import threading
57 57 import killdaemons as killmod
58 58
59 59 processlock = threading.Lock()
60 60
61 61 closefds = os.name == 'posix'
62 62 def Popen4(cmd, wd, timeout):
63 63 processlock.acquire()
64 64 p = subprocess.Popen(cmd, shell=True, bufsize=-1, cwd=wd,
65 65 close_fds=closefds,
66 66 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
67 67 stderr=subprocess.STDOUT)
68 68 processlock.release()
69 69
70 70 p.fromchild = p.stdout
71 71 p.tochild = p.stdin
72 72 p.childerr = p.stderr
73 73
74 74 p.timeout = False
75 75 if timeout:
76 76 def t():
77 77 start = time.time()
78 78 while time.time() - start < timeout and p.returncode is None:
79 79 time.sleep(.1)
80 80 p.timeout = True
81 81 if p.returncode is None:
82 82 terminate(p)
83 83 threading.Thread(target=t).start()
84 84
85 85 return p
86 86
87 87 # reserved exit code to skip test (used by hghave)
88 88 SKIPPED_STATUS = 80
89 89 SKIPPED_PREFIX = 'skipped: '
90 90 FAILED_PREFIX = 'hghave check failed: '
91 91 PYTHON = sys.executable.replace('\\', '/')
92 92 IMPL_PATH = 'PYTHONPATH'
93 93 if 'java' in sys.platform:
94 94 IMPL_PATH = 'JYTHONPATH'
95 95
96 96 requiredtools = ["python", "diff", "grep", "unzip", "gunzip", "bunzip2", "sed"]
97 97
98 98 defaults = {
99 99 'jobs': ('HGTEST_JOBS', 1),
100 100 'timeout': ('HGTEST_TIMEOUT', 180),
101 101 'port': ('HGTEST_PORT', 20059),
102 102 'shell': ('HGTEST_SHELL', 'sh'),
103 103 }
104 104
105 105 def parselistfiles(files, listtype, warn=True):
106 106 entries = dict()
107 107 for filename in files:
108 108 try:
109 109 path = os.path.expanduser(os.path.expandvars(filename))
110 110 f = open(path, "r")
111 111 except IOError, err:
112 112 if err.errno != errno.ENOENT:
113 113 raise
114 114 if warn:
115 115 print "warning: no such %s file: %s" % (listtype, filename)
116 116 continue
117 117
118 118 for line in f.readlines():
119 119 line = line.split('#', 1)[0].strip()
120 120 if line:
121 121 entries[line] = filename
122 122
123 123 f.close()
124 124 return entries
125 125
126 126 def parseargs():
127 127 parser = optparse.OptionParser("%prog [options] [tests]")
128 128
129 129 # keep these sorted
130 130 parser.add_option("--blacklist", action="append",
131 131 help="skip tests listed in the specified blacklist file")
132 132 parser.add_option("--whitelist", action="append",
133 133 help="always run tests listed in the specified whitelist file")
134 134 parser.add_option("-C", "--annotate", action="store_true",
135 135 help="output files annotated with coverage")
136 136 parser.add_option("--child", type="int",
137 137 help="run as child process, summary to given fd")
138 138 parser.add_option("-c", "--cover", action="store_true",
139 139 help="print a test coverage report")
140 140 parser.add_option("-d", "--debug", action="store_true",
141 141 help="debug mode: write output of test scripts to console"
142 142 " rather than capturing and diff'ing it (disables timeout)")
143 143 parser.add_option("-f", "--first", action="store_true",
144 144 help="exit on the first test failure")
145 145 parser.add_option("-H", "--htmlcov", action="store_true",
146 146 help="create an HTML report of the coverage of the files")
147 147 parser.add_option("--inotify", action="store_true",
148 148 help="enable inotify extension when running tests")
149 149 parser.add_option("-i", "--interactive", action="store_true",
150 150 help="prompt to accept changed output")
151 151 parser.add_option("-j", "--jobs", type="int",
152 152 help="number of jobs to run in parallel"
153 153 " (default: $%s or %d)" % defaults['jobs'])
154 154 parser.add_option("--keep-tmpdir", action="store_true",
155 155 help="keep temporary directory after running tests")
156 156 parser.add_option("-k", "--keywords",
157 157 help="run tests matching keywords")
158 158 parser.add_option("-l", "--local", action="store_true",
159 159 help="shortcut for --with-hg=<testdir>/../hg")
160 160 parser.add_option("-n", "--nodiff", action="store_true",
161 161 help="skip showing test changes")
162 162 parser.add_option("-p", "--port", type="int",
163 163 help="port on which servers should listen"
164 164 " (default: $%s or %d)" % defaults['port'])
165 165 parser.add_option("--pure", action="store_true",
166 166 help="use pure Python code instead of C extensions")
167 167 parser.add_option("-R", "--restart", action="store_true",
168 168 help="restart at last error")
169 169 parser.add_option("-r", "--retest", action="store_true",
170 170 help="retest failed tests")
171 171 parser.add_option("-S", "--noskips", action="store_true",
172 172 help="don't report skip tests verbosely")
173 173 parser.add_option("--shell", type="string",
174 174 help="shell to use (default: $%s or %s)" % defaults['shell'])
175 175 parser.add_option("-t", "--timeout", type="int",
176 176 help="kill errant tests after TIMEOUT seconds"
177 177 " (default: $%s or %d)" % defaults['timeout'])
178 178 parser.add_option("--tmpdir", type="string",
179 179 help="run tests in the given temporary directory"
180 180 " (implies --keep-tmpdir)")
181 181 parser.add_option("-v", "--verbose", action="store_true",
182 182 help="output verbose messages")
183 183 parser.add_option("--view", type="string",
184 184 help="external diff viewer")
185 185 parser.add_option("--with-hg", type="string",
186 186 metavar="HG",
187 187 help="test using specified hg script rather than a "
188 188 "temporary installation")
189 189 parser.add_option("-3", "--py3k-warnings", action="store_true",
190 190 help="enable Py3k warnings on Python 2.6+")
191 191 parser.add_option('--extra-config-opt', action="append",
192 192 help='set the given config opt in the test hgrc')
193 193
194 194 for option, (envvar, default) in defaults.items():
195 195 defaults[option] = type(default)(os.environ.get(envvar, default))
196 196 parser.set_defaults(**defaults)
197 197 (options, args) = parser.parse_args()
198 198
199 199 # jython is always pure
200 200 if 'java' in sys.platform or '__pypy__' in sys.modules:
201 201 options.pure = True
202 202
203 203 if options.with_hg:
204 204 options.with_hg = os.path.expanduser(options.with_hg)
205 205 if not (os.path.isfile(options.with_hg) and
206 206 os.access(options.with_hg, os.X_OK)):
207 207 parser.error('--with-hg must specify an executable hg script')
208 208 if not os.path.basename(options.with_hg) == 'hg':
209 209 sys.stderr.write('warning: --with-hg should specify an hg script\n')
210 210 if options.local:
211 211 testdir = os.path.dirname(os.path.realpath(sys.argv[0]))
212 212 hgbin = os.path.join(os.path.dirname(testdir), 'hg')
213 213 if os.name != 'nt' and not os.access(hgbin, os.X_OK):
214 214 parser.error('--local specified, but %r not found or not executable'
215 215 % hgbin)
216 216 options.with_hg = hgbin
217 217
218 218 options.anycoverage = options.cover or options.annotate or options.htmlcov
219 219 if options.anycoverage:
220 220 try:
221 221 import coverage
222 222 covver = version.StrictVersion(coverage.__version__).version
223 223 if covver < (3, 3):
224 224 parser.error('coverage options require coverage 3.3 or later')
225 225 except ImportError:
226 226 parser.error('coverage options now require the coverage package')
227 227
228 228 if options.anycoverage and options.local:
229 229 # this needs some path mangling somewhere, I guess
230 230 parser.error("sorry, coverage options do not work when --local "
231 231 "is specified")
232 232
233 233 global vlog
234 234 if options.verbose:
235 235 if options.jobs > 1 or options.child is not None:
236 236 pid = "[%d]" % os.getpid()
237 237 else:
238 238 pid = None
239 239 def vlog(*msg):
240 240 iolock.acquire()
241 241 if pid:
242 242 print pid,
243 243 for m in msg:
244 244 print m,
245 245 print
246 246 sys.stdout.flush()
247 247 iolock.release()
248 248 else:
249 249 vlog = lambda *msg: None
250 250
251 251 if options.tmpdir:
252 252 options.tmpdir = os.path.expanduser(options.tmpdir)
253 253
254 254 if options.jobs < 1:
255 255 parser.error('--jobs must be positive')
256 256 if options.interactive and options.jobs > 1:
257 257 print '(--interactive overrides --jobs)'
258 258 options.jobs = 1
259 259 if options.interactive and options.debug:
260 260 parser.error("-i/--interactive and -d/--debug are incompatible")
261 261 if options.debug:
262 262 if options.timeout != defaults['timeout']:
263 263 sys.stderr.write(
264 264 'warning: --timeout option ignored with --debug\n')
265 265 options.timeout = 0
266 266 if options.py3k_warnings:
267 267 if sys.version_info[:2] < (2, 6) or sys.version_info[:2] >= (3, 0):
268 268 parser.error('--py3k-warnings can only be used on Python 2.6+')
269 269 if options.blacklist:
270 270 options.blacklist = parselistfiles(options.blacklist, 'blacklist')
271 271 if options.whitelist:
272 272 options.whitelisted = parselistfiles(options.whitelist, 'whitelist',
273 273 warn=options.child is None)
274 274 else:
275 275 options.whitelisted = {}
276 276
277 277 return (options, args)
278 278
279 279 def rename(src, dst):
280 280 """Like os.rename(), trade atomicity and opened files friendliness
281 281 for existing destination support.
282 282 """
283 283 shutil.copy(src, dst)
284 284 os.remove(src)
285 285
286 286 def parsehghaveoutput(lines):
287 287 '''Parse hghave log lines.
288 288 Return tuple of lists (missing, failed):
289 289 * the missing/unknown features
290 290 * the features for which existence check failed'''
291 291 missing = []
292 292 failed = []
293 293 for line in lines:
294 294 if line.startswith(SKIPPED_PREFIX):
295 295 line = line.splitlines()[0]
296 296 missing.append(line[len(SKIPPED_PREFIX):])
297 297 elif line.startswith(FAILED_PREFIX):
298 298 line = line.splitlines()[0]
299 299 failed.append(line[len(FAILED_PREFIX):])
300 300
301 301 return missing, failed
302 302
303 303 def showdiff(expected, output, ref, err):
304 304 print
305 305 for line in difflib.unified_diff(expected, output, ref, err):
306 306 sys.stdout.write(line)
307 307
308 308 def findprogram(program):
309 309 """Search PATH for a executable program"""
310 310 for p in os.environ.get('PATH', os.defpath).split(os.pathsep):
311 311 name = os.path.join(p, program)
312 312 if os.name == 'nt' or os.access(name, os.X_OK):
313 313 return name
314 314 return None
315 315
316 316 def checktools():
317 317 # Before we go any further, check for pre-requisite tools
318 318 # stuff from coreutils (cat, rm, etc) are not tested
319 319 for p in requiredtools:
320 320 if os.name == 'nt':
321 321 p += '.exe'
322 322 found = findprogram(p)
323 323 if found:
324 324 vlog("# Found prerequisite", p, "at", found)
325 325 else:
326 326 print "WARNING: Did not find prerequisite tool: "+p
327 327
328 328 def terminate(proc):
329 329 """Terminate subprocess (with fallback for Python versions < 2.6)"""
330 330 vlog('# Terminating process %d' % proc.pid)
331 331 try:
332 332 getattr(proc, 'terminate', lambda : os.kill(proc.pid, signal.SIGTERM))()
333 333 except OSError:
334 334 pass
335 335
336 336 def killdaemons():
337 337 return killmod.killdaemons(DAEMON_PIDS, tryhard=False, remove=True,
338 338 logfn=vlog)
339 339
340 340 def cleanup(options):
341 341 if not options.keep_tmpdir:
342 342 vlog("# Cleaning up HGTMP", HGTMP)
343 343 shutil.rmtree(HGTMP, True)
344 344
345 345 def usecorrectpython():
346 346 # some tests run python interpreter. they must use same
347 347 # interpreter we use or bad things will happen.
348 348 exedir, exename = os.path.split(sys.executable)
349 349 if exename in ('python', 'python.exe'):
350 350 path = findprogram(exename)
351 351 if os.path.dirname(path) == exedir:
352 352 return
353 353 else:
354 354 exename = 'python'
355 355 vlog('# Making python executable in test path use correct Python')
356 356 mypython = os.path.join(BINDIR, exename)
357 357 try:
358 358 os.symlink(sys.executable, mypython)
359 359 except AttributeError:
360 360 # windows fallback
361 361 shutil.copyfile(sys.executable, mypython)
362 362 shutil.copymode(sys.executable, mypython)
363 363
364 364 def installhg(options):
365 365 vlog("# Performing temporary installation of HG")
366 366 installerrs = os.path.join("tests", "install.err")
367 367 pure = options.pure and "--pure" or ""
368 368
369 369 # Run installer in hg root
370 370 script = os.path.realpath(sys.argv[0])
371 371 hgroot = os.path.dirname(os.path.dirname(script))
372 372 os.chdir(hgroot)
373 373 nohome = '--home=""'
374 374 if os.name == 'nt':
375 375 # The --home="" trick works only on OS where os.sep == '/'
376 376 # because of a distutils convert_path() fast-path. Avoid it at
377 377 # least on Windows for now, deal with .pydistutils.cfg bugs
378 378 # when they happen.
379 379 nohome = ''
380 380 cmd = ('%s setup.py %s clean --all'
381 381 ' build --build-base="%s"'
382 382 ' install --force --prefix="%s" --install-lib="%s"'
383 383 ' --install-scripts="%s" %s >%s 2>&1'
384 384 % (sys.executable, pure, os.path.join(HGTMP, "build"),
385 385 INST, PYTHONDIR, BINDIR, nohome, installerrs))
386 386 vlog("# Running", cmd)
387 387 if os.system(cmd) == 0:
388 388 if not options.verbose:
389 389 os.remove(installerrs)
390 390 else:
391 391 f = open(installerrs)
392 392 for line in f:
393 393 print line,
394 394 f.close()
395 395 sys.exit(1)
396 396 os.chdir(TESTDIR)
397 397
398 398 usecorrectpython()
399 399
400 400 vlog("# Installing dummy diffstat")
401 401 f = open(os.path.join(BINDIR, 'diffstat'), 'w')
402 402 f.write('#!' + sys.executable + '\n'
403 403 'import sys\n'
404 404 'files = 0\n'
405 405 'for line in sys.stdin:\n'
406 406 ' if line.startswith("diff "):\n'
407 407 ' files += 1\n'
408 408 'sys.stdout.write("files patched: %d\\n" % files)\n')
409 409 f.close()
410 410 os.chmod(os.path.join(BINDIR, 'diffstat'), 0700)
411 411
412 412 if options.py3k_warnings and not options.anycoverage:
413 413 vlog("# Updating hg command to enable Py3k Warnings switch")
414 414 f = open(os.path.join(BINDIR, 'hg'), 'r')
415 415 lines = [line.rstrip() for line in f]
416 416 lines[0] += ' -3'
417 417 f.close()
418 418 f = open(os.path.join(BINDIR, 'hg'), 'w')
419 419 for line in lines:
420 420 f.write(line + '\n')
421 421 f.close()
422 422
423 423 hgbat = os.path.join(BINDIR, 'hg.bat')
424 424 if os.path.isfile(hgbat):
425 425 # hg.bat expects to be put in bin/scripts while run-tests.py
426 426 # installation layout put it in bin/ directly. Fix it
427 427 f = open(hgbat, 'rb')
428 428 data = f.read()
429 429 f.close()
430 430 if '"%~dp0..\python" "%~dp0hg" %*' in data:
431 431 data = data.replace('"%~dp0..\python" "%~dp0hg" %*',
432 432 '"%~dp0python" "%~dp0hg" %*')
433 433 f = open(hgbat, 'wb')
434 434 f.write(data)
435 435 f.close()
436 436 else:
437 437 print 'WARNING: cannot fix hg.bat reference to python.exe'
438 438
439 439 if options.anycoverage:
440 440 custom = os.path.join(TESTDIR, 'sitecustomize.py')
441 441 target = os.path.join(PYTHONDIR, 'sitecustomize.py')
442 442 vlog('# Installing coverage trigger to %s' % target)
443 443 shutil.copyfile(custom, target)
444 444 rc = os.path.join(TESTDIR, '.coveragerc')
445 445 vlog('# Installing coverage rc to %s' % rc)
446 446 os.environ['COVERAGE_PROCESS_START'] = rc
447 447 fn = os.path.join(INST, '..', '.coverage')
448 448 os.environ['COVERAGE_FILE'] = fn
449 449
450 450 def outputcoverage(options):
451 451
452 452 vlog('# Producing coverage report')
453 453 os.chdir(PYTHONDIR)
454 454
455 455 def covrun(*args):
456 456 cmd = 'coverage %s' % ' '.join(args)
457 457 vlog('# Running: %s' % cmd)
458 458 os.system(cmd)
459 459
460 460 if options.child:
461 461 return
462 462
463 463 covrun('-c')
464 464 omit = ','.join(os.path.join(x, '*') for x in [BINDIR, TESTDIR])
465 465 covrun('-i', '-r', '"--omit=%s"' % omit) # report
466 466 if options.htmlcov:
467 467 htmldir = os.path.join(TESTDIR, 'htmlcov')
468 468 covrun('-i', '-b', '"--directory=%s"' % htmldir, '"--omit=%s"' % omit)
469 469 if options.annotate:
470 470 adir = os.path.join(TESTDIR, 'annotated')
471 471 if not os.path.isdir(adir):
472 472 os.mkdir(adir)
473 473 covrun('-i', '-a', '"--directory=%s"' % adir, '"--omit=%s"' % omit)
474 474
475 475 def pytest(test, wd, options, replacements):
476 476 py3kswitch = options.py3k_warnings and ' -3' or ''
477 477 cmd = '%s%s "%s"' % (PYTHON, py3kswitch, test)
478 478 vlog("# Running", cmd)
479 479 if os.name == 'nt':
480 480 replacements.append((r'\r\n', '\n'))
481 481 return run(cmd, wd, options, replacements)
482 482
483 def shtest(test, wd, options, replacements):
484 cmd = '%s "%s"' % (options.shell, test)
485 vlog("# Running", cmd)
486 return run(cmd, wd, options, replacements)
487
488 483 needescape = re.compile(r'[\x00-\x08\x0b-\x1f\x7f-\xff]').search
489 484 escapesub = re.compile(r'[\x00-\x08\x0b-\x1f\\\x7f-\xff]').sub
490 485 escapemap = dict((chr(i), r'\x%02x' % i) for i in range(256))
491 486 escapemap.update({'\\': '\\\\', '\r': r'\r'})
492 487 def escapef(m):
493 488 return escapemap[m.group(0)]
494 489 def stringescape(s):
495 490 return escapesub(escapef, s)
496 491
497 492 def rematch(el, l):
498 493 try:
499 494 # use \Z to ensure that the regex matches to the end of the string
500 495 if os.name == 'nt':
501 496 return re.match(el + r'\r?\n\Z', l)
502 497 return re.match(el + r'\n\Z', l)
503 498 except re.error:
504 499 # el is an invalid regex
505 500 return False
506 501
507 502 def globmatch(el, l):
508 503 # The only supported special characters are * and ? plus / which also
509 504 # matches \ on windows. Escaping of these caracters is supported.
510 505 i, n = 0, len(el)
511 506 res = ''
512 507 while i < n:
513 508 c = el[i]
514 509 i += 1
515 510 if c == '\\' and el[i] in '*?\\/':
516 511 res += el[i - 1:i + 1]
517 512 i += 1
518 513 elif c == '*':
519 514 res += '.*'
520 515 elif c == '?':
521 516 res += '.'
522 517 elif c == '/' and os.name == 'nt':
523 518 res += '[/\\\\]'
524 519 else:
525 520 res += re.escape(c)
526 521 return rematch(res, l)
527 522
528 523 def linematch(el, l):
529 524 if el == l: # perfect match (fast)
530 525 return True
531 526 if el:
532 527 if el.endswith(" (esc)\n"):
533 528 el = el[:-7].decode('string-escape') + '\n'
534 529 if el == l or os.name == 'nt' and el[:-1] + '\r\n' == l:
535 530 return True
536 531 if (el.endswith(" (re)\n") and rematch(el[:-6], l) or
537 532 el.endswith(" (glob)\n") and globmatch(el[:-8], l)):
538 533 return True
539 534 return False
540 535
541 536 def tsttest(test, wd, options, replacements):
542 537 # We generate a shell script which outputs unique markers to line
543 538 # up script results with our source. These markers include input
544 539 # line number and the last return code
545 540 salt = "SALT" + str(time.time())
546 541 def addsalt(line, inpython):
547 542 if inpython:
548 543 script.append('%s %d 0\n' % (salt, line))
549 544 else:
550 545 script.append('echo %s %s $?\n' % (salt, line))
551 546
552 547 # After we run the shell script, we re-unify the script output
553 548 # with non-active parts of the source, with synchronization by our
554 549 # SALT line number markers. The after table contains the
555 550 # non-active components, ordered by line number
556 551 after = {}
557 552 pos = prepos = -1
558 553
559 554 # Expected shellscript output
560 555 expected = {}
561 556
562 557 # We keep track of whether or not we're in a Python block so we
563 558 # can generate the surrounding doctest magic
564 559 inpython = False
565 560
566 561 # True or False when in a true or false conditional section
567 562 skipping = None
568 563
569 564 def hghave(reqs):
570 565 # TODO: do something smarter when all other uses of hghave is gone
571 566 tdir = TESTDIR.replace('\\', '/')
572 567 proc = Popen4('%s -c "%s/hghave %s"' %
573 568 (options.shell, tdir, ' '.join(reqs)), wd, 0)
574 569 proc.communicate()
575 570 ret = proc.wait()
576 571 if wifexited(ret):
577 572 ret = os.WEXITSTATUS(ret)
578 573 return ret == 0
579 574
580 575 f = open(test)
581 576 t = f.readlines()
582 577 f.close()
583 578
584 579 script = []
585 580 if options.debug:
586 581 script.append('set -x\n')
587 582 if os.getenv('MSYSTEM'):
588 583 script.append('alias pwd="pwd -W"\n')
589 584 for n, l in enumerate(t):
590 585 if not l.endswith('\n'):
591 586 l += '\n'
592 587 if l.startswith('#if'):
593 588 if skipping is not None:
594 589 after.setdefault(pos, []).append(' !!! nested #if\n')
595 590 skipping = not hghave(l.split()[1:])
596 591 after.setdefault(pos, []).append(l)
597 592 elif l.startswith('#else'):
598 593 if skipping is None:
599 594 after.setdefault(pos, []).append(' !!! missing #if\n')
600 595 skipping = not skipping
601 596 after.setdefault(pos, []).append(l)
602 597 elif l.startswith('#endif'):
603 598 if skipping is None:
604 599 after.setdefault(pos, []).append(' !!! missing #if\n')
605 600 skipping = None
606 601 after.setdefault(pos, []).append(l)
607 602 elif skipping:
608 603 after.setdefault(pos, []).append(l)
609 604 elif l.startswith(' >>> '): # python inlines
610 605 after.setdefault(pos, []).append(l)
611 606 prepos = pos
612 607 pos = n
613 608 if not inpython:
614 609 # we've just entered a Python block, add the header
615 610 inpython = True
616 611 addsalt(prepos, False) # make sure we report the exit code
617 612 script.append('%s -m heredoctest <<EOF\n' % PYTHON)
618 613 addsalt(n, True)
619 614 script.append(l[2:])
620 615 elif l.startswith(' ... '): # python inlines
621 616 after.setdefault(prepos, []).append(l)
622 617 script.append(l[2:])
623 618 elif l.startswith(' $ '): # commands
624 619 if inpython:
625 620 script.append("EOF\n")
626 621 inpython = False
627 622 after.setdefault(pos, []).append(l)
628 623 prepos = pos
629 624 pos = n
630 625 addsalt(n, False)
631 626 cmd = l[4:].split()
632 627 if len(cmd) == 2 and cmd[0] == 'cd':
633 628 l = ' $ cd %s || exit 1\n' % cmd[1]
634 629 script.append(l[4:])
635 630 elif l.startswith(' > '): # continuations
636 631 after.setdefault(prepos, []).append(l)
637 632 script.append(l[4:])
638 633 elif l.startswith(' '): # results
639 634 # queue up a list of expected results
640 635 expected.setdefault(pos, []).append(l[2:])
641 636 else:
642 637 if inpython:
643 638 script.append("EOF\n")
644 639 inpython = False
645 640 # non-command/result - queue up for merged output
646 641 after.setdefault(pos, []).append(l)
647 642
648 643 if inpython:
649 644 script.append("EOF\n")
650 645 if skipping is not None:
651 646 after.setdefault(pos, []).append(' !!! missing #endif\n')
652 647 addsalt(n + 1, False)
653 648
654 649 # Write out the script and execute it
655 650 fd, name = tempfile.mkstemp(suffix='hg-tst')
656 651 try:
657 652 for l in script:
658 653 os.write(fd, l)
659 654 os.close(fd)
660 655
661 656 cmd = '%s "%s"' % (options.shell, name)
662 657 vlog("# Running", cmd)
663 658 exitcode, output = run(cmd, wd, options, replacements)
664 659 # do not merge output if skipped, return hghave message instead
665 660 # similarly, with --debug, output is None
666 661 if exitcode == SKIPPED_STATUS or output is None:
667 662 return exitcode, output
668 663 finally:
669 664 os.remove(name)
670 665
671 666 # Merge the script output back into a unified test
672 667
673 668 pos = -1
674 669 postout = []
675 670 ret = 0
676 671 for l in output:
677 672 lout, lcmd = l, None
678 673 if salt in l:
679 674 lout, lcmd = l.split(salt, 1)
680 675
681 676 if lout:
682 677 if not lout.endswith('\n'):
683 678 lout += ' (no-eol)\n'
684 679
685 680 # find the expected output at the current position
686 681 el = None
687 682 if pos in expected and expected[pos]:
688 683 el = expected[pos].pop(0)
689 684
690 685 if linematch(el, lout):
691 686 postout.append(" " + el)
692 687 else:
693 688 if needescape(lout):
694 689 lout = stringescape(lout.rstrip('\n')) + " (esc)\n"
695 690 postout.append(" " + lout) # let diff deal with it
696 691
697 692 if lcmd:
698 693 # add on last return code
699 694 ret = int(lcmd.split()[1])
700 695 if ret != 0:
701 696 postout.append(" [%s]\n" % ret)
702 697 if pos in after:
703 698 # merge in non-active test bits
704 699 postout += after.pop(pos)
705 700 pos = int(lcmd.split()[0])
706 701
707 702 if pos in after:
708 703 postout += after.pop(pos)
709 704
710 705 return exitcode, postout
711 706
712 707 wifexited = getattr(os, "WIFEXITED", lambda x: False)
713 708 def run(cmd, wd, options, replacements):
714 709 """Run command in a sub-process, capturing the output (stdout and stderr).
715 710 Return a tuple (exitcode, output). output is None in debug mode."""
716 711 # TODO: Use subprocess.Popen if we're running on Python 2.4
717 712 if options.debug:
718 713 proc = subprocess.Popen(cmd, shell=True, cwd=wd)
719 714 ret = proc.wait()
720 715 return (ret, None)
721 716
722 717 proc = Popen4(cmd, wd, options.timeout)
723 718 def cleanup():
724 719 terminate(proc)
725 720 ret = proc.wait()
726 721 if ret == 0:
727 722 ret = signal.SIGTERM << 8
728 723 killdaemons()
729 724 return ret
730 725
731 726 output = ''
732 727 proc.tochild.close()
733 728
734 729 try:
735 730 output = proc.fromchild.read()
736 731 except KeyboardInterrupt:
737 732 vlog('# Handling keyboard interrupt')
738 733 cleanup()
739 734 raise
740 735
741 736 ret = proc.wait()
742 737 if wifexited(ret):
743 738 ret = os.WEXITSTATUS(ret)
744 739
745 740 if proc.timeout:
746 741 ret = 'timeout'
747 742
748 743 if ret:
749 744 killdaemons()
750 745
751 746 for s, r in replacements:
752 747 output = re.sub(s, r, output)
753 748 return ret, output.splitlines(True)
754 749
755 750 def runone(options, test):
756 751 '''tristate output:
757 752 None -> skipped
758 753 True -> passed
759 754 False -> failed'''
760 755
761 756 global results, resultslock, iolock
762 757
763 758 testpath = os.path.join(TESTDIR, test)
764 759
765 760 def result(l, e):
766 761 resultslock.acquire()
767 762 results[l].append(e)
768 763 resultslock.release()
769 764
770 765 def skip(msg):
771 766 if not options.verbose:
772 767 result('s', (test, msg))
773 768 else:
774 769 iolock.acquire()
775 770 print "\nSkipping %s: %s" % (testpath, msg)
776 771 iolock.release()
777 772 return None
778 773
779 774 def fail(msg, ret):
780 775 if not options.nodiff:
781 776 iolock.acquire()
782 777 print "\nERROR: %s %s" % (testpath, msg)
783 778 iolock.release()
784 779 if (not ret and options.interactive
785 780 and os.path.exists(testpath + ".err")):
786 781 iolock.acquire()
787 782 print "Accept this change? [n] ",
788 783 answer = sys.stdin.readline().strip()
789 784 iolock.release()
790 785 if answer.lower() in "y yes".split():
791 786 if test.endswith(".t"):
792 787 rename(testpath + ".err", testpath)
793 788 else:
794 789 rename(testpath + ".err", testpath + ".out")
795 790 result('p', test)
796 791 return
797 792 result('f', (test, msg))
798 793
799 794 def success():
800 795 result('p', test)
801 796
802 797 def ignore(msg):
803 798 result('i', (test, msg))
804 799
805 800 if (os.path.basename(test).startswith("test-") and '~' not in test and
806 801 ('.' not in test or test.endswith('.py') or
807 802 test.endswith('.bat') or test.endswith('.t'))):
808 803 if not os.path.exists(test):
809 804 skip("doesn't exist")
810 805 return None
811 806 else:
812 807 vlog('# Test file', test, 'not supported, ignoring')
813 808 return None # not a supported test, don't record
814 809
815 810 if not (options.whitelisted and test in options.whitelisted):
816 811 if options.blacklist and test in options.blacklist:
817 812 skip("blacklisted")
818 813 return None
819 814
820 815 if options.retest and not os.path.exists(test + ".err"):
821 816 ignore("not retesting")
822 817 return None
823 818
824 819 if options.keywords:
825 820 fp = open(test)
826 821 t = fp.read().lower() + test.lower()
827 822 fp.close()
828 823 for k in options.keywords.lower().split():
829 824 if k in t:
830 825 break
831 826 else:
832 827 ignore("doesn't match keyword")
833 828 return None
834 829
835 830 vlog("# Test", test)
836 831
837 832 # create a fresh hgrc
838 833 hgrc = open(HGRCPATH, 'w+')
839 834 hgrc.write('[ui]\n')
840 835 hgrc.write('slash = True\n')
841 836 hgrc.write('[defaults]\n')
842 837 hgrc.write('backout = -d "0 0"\n')
843 838 hgrc.write('commit = -d "0 0"\n')
844 839 hgrc.write('tag = -d "0 0"\n')
845 840 if options.inotify:
846 841 hgrc.write('[extensions]\n')
847 842 hgrc.write('inotify=\n')
848 843 hgrc.write('[inotify]\n')
849 844 hgrc.write('pidfile=%s\n' % DAEMON_PIDS)
850 845 hgrc.write('appendpid=True\n')
851 846 if options.extra_config_opt:
852 847 for opt in options.extra_config_opt:
853 848 section, key = opt.split('.', 1)
854 849 assert '=' in key, ('extra config opt %s must '
855 850 'have an = for assignment' % opt)
856 851 hgrc.write('[%s]\n%s\n' % (section, key))
857 852 hgrc.close()
858 853
859 854 ref = os.path.join(TESTDIR, test+".out")
860 855 err = os.path.join(TESTDIR, test+".err")
861 856 if os.path.exists(err):
862 857 os.remove(err) # Remove any previous output files
863 858 try:
864 859 tf = open(testpath)
865 860 firstline = tf.readline().rstrip()
866 861 tf.close()
867 862 except IOError:
868 863 firstline = ''
869 864 lctest = test.lower()
870 865
871 866 if lctest.endswith('.py') or firstline == '#!/usr/bin/env python':
872 867 runner = pytest
873 868 elif lctest.endswith('.t'):
874 869 runner = tsttest
875 870 ref = testpath
876 871 else:
877 # do not try to run non-executable programs
878 if not os.access(testpath, os.X_OK):
879 return skip("not executable")
880 runner = shtest
872 return skip("unknown test type")
881 873
882 874 # Make a tmp subdirectory to work in
883 875 testtmp = os.environ["TESTTMP"] = os.environ["HOME"] = \
884 876 os.path.join(HGTMP, os.path.basename(test))
885 877
886 878 replacements = [
887 879 (r':%s\b' % options.port, ':$HGPORT'),
888 880 (r':%s\b' % (options.port + 1), ':$HGPORT1'),
889 881 (r':%s\b' % (options.port + 2), ':$HGPORT2'),
890 882 ]
891 883 if os.name == 'nt':
892 884 replacements.append(
893 885 (''.join(c.isalpha() and '[%s%s]' % (c.lower(), c.upper()) or
894 886 c in '/\\' and r'[/\\]' or
895 887 c.isdigit() and c or
896 888 '\\' + c
897 889 for c in testtmp), '$TESTTMP'))
898 890 else:
899 891 replacements.append((re.escape(testtmp), '$TESTTMP'))
900 892
901 893 os.mkdir(testtmp)
902 894 ret, out = runner(testpath, testtmp, options, replacements)
903 895 vlog("# Ret was:", ret)
904 896
905 897 mark = '.'
906 898
907 899 skipped = (ret == SKIPPED_STATUS)
908 900
909 901 # If we're not in --debug mode and reference output file exists,
910 902 # check test output against it.
911 903 if options.debug:
912 904 refout = None # to match "out is None"
913 905 elif os.path.exists(ref):
914 906 f = open(ref, "r")
915 907 refout = f.read().splitlines(True)
916 908 f.close()
917 909 else:
918 910 refout = []
919 911
920 912 if (ret != 0 or out != refout) and not skipped and not options.debug:
921 913 # Save errors to a file for diagnosis
922 914 f = open(err, "wb")
923 915 for line in out:
924 916 f.write(line)
925 917 f.close()
926 918
927 919 def describe(ret):
928 920 if ret < 0:
929 921 return 'killed by signal %d' % -ret
930 922 return 'returned error code %d' % ret
931 923
932 924 if skipped:
933 925 mark = 's'
934 926 if out is None: # debug mode: nothing to parse
935 927 missing = ['unknown']
936 928 failed = None
937 929 else:
938 930 missing, failed = parsehghaveoutput(out)
939 931 if not missing:
940 932 missing = ['irrelevant']
941 933 if failed:
942 934 fail("hghave failed checking for %s" % failed[-1], ret)
943 935 skipped = False
944 936 else:
945 937 skip(missing[-1])
946 938 elif ret == 'timeout':
947 939 mark = 't'
948 940 fail("timed out", ret)
949 941 elif out != refout:
950 942 mark = '!'
951 943 if not options.nodiff:
952 944 iolock.acquire()
953 945 if options.view:
954 946 os.system("%s %s %s" % (options.view, ref, err))
955 947 else:
956 948 showdiff(refout, out, ref, err)
957 949 iolock.release()
958 950 if ret:
959 951 fail("output changed and " + describe(ret), ret)
960 952 else:
961 953 fail("output changed", ret)
962 954 ret = 1
963 955 elif ret:
964 956 mark = '!'
965 957 fail(describe(ret), ret)
966 958 else:
967 959 success()
968 960
969 961 if not options.verbose:
970 962 iolock.acquire()
971 963 sys.stdout.write(mark)
972 964 sys.stdout.flush()
973 965 iolock.release()
974 966
975 967 killdaemons()
976 968
977 969 if not options.keep_tmpdir:
978 970 shutil.rmtree(testtmp, True)
979 971 if skipped:
980 972 return None
981 973 return ret == 0
982 974
983 975 _hgpath = None
984 976
985 977 def _gethgpath():
986 978 """Return the path to the mercurial package that is actually found by
987 979 the current Python interpreter."""
988 980 global _hgpath
989 981 if _hgpath is not None:
990 982 return _hgpath
991 983
992 984 cmd = '%s -c "import mercurial; print mercurial.__path__[0]"'
993 985 pipe = os.popen(cmd % PYTHON)
994 986 try:
995 987 _hgpath = pipe.read().strip()
996 988 finally:
997 989 pipe.close()
998 990 return _hgpath
999 991
1000 992 def _checkhglib(verb):
1001 993 """Ensure that the 'mercurial' package imported by python is
1002 994 the one we expect it to be. If not, print a warning to stderr."""
1003 995 expecthg = os.path.join(PYTHONDIR, 'mercurial')
1004 996 actualhg = _gethgpath()
1005 997 if os.path.abspath(actualhg) != os.path.abspath(expecthg):
1006 998 sys.stderr.write('warning: %s with unexpected mercurial lib: %s\n'
1007 999 ' (expected %s)\n'
1008 1000 % (verb, actualhg, expecthg))
1009 1001
1010 1002 def runchildren(options, tests):
1011 1003 if INST:
1012 1004 installhg(options)
1013 1005 _checkhglib("Testing")
1014 1006
1015 1007 optcopy = dict(options.__dict__)
1016 1008 optcopy['jobs'] = 1
1017 1009
1018 1010 # Because whitelist has to override keyword matches, we have to
1019 1011 # actually load the whitelist in the children as well, so we allow
1020 1012 # the list of whitelist files to pass through and be parsed in the
1021 1013 # children, but not the dict of whitelisted tests resulting from
1022 1014 # the parse, used here to override blacklisted tests.
1023 1015 whitelist = optcopy['whitelisted'] or []
1024 1016 del optcopy['whitelisted']
1025 1017
1026 1018 blacklist = optcopy['blacklist'] or []
1027 1019 del optcopy['blacklist']
1028 1020 blacklisted = []
1029 1021
1030 1022 if optcopy['with_hg'] is None:
1031 1023 optcopy['with_hg'] = os.path.join(BINDIR, "hg")
1032 1024 optcopy.pop('anycoverage', None)
1033 1025
1034 1026 opts = []
1035 1027 for opt, value in optcopy.iteritems():
1036 1028 name = '--' + opt.replace('_', '-')
1037 1029 if value is True:
1038 1030 opts.append(name)
1039 1031 elif isinstance(value, list):
1040 1032 for v in value:
1041 1033 opts.append(name + '=' + str(v))
1042 1034 elif value is not None:
1043 1035 opts.append(name + '=' + str(value))
1044 1036
1045 1037 tests.reverse()
1046 1038 jobs = [[] for j in xrange(options.jobs)]
1047 1039 while tests:
1048 1040 for job in jobs:
1049 1041 if not tests:
1050 1042 break
1051 1043 test = tests.pop()
1052 1044 if test not in whitelist and test in blacklist:
1053 1045 blacklisted.append(test)
1054 1046 else:
1055 1047 job.append(test)
1056 1048 fps = {}
1057 1049
1058 1050 for j, job in enumerate(jobs):
1059 1051 if not job:
1060 1052 continue
1061 1053 rfd, wfd = os.pipe()
1062 1054 childopts = ['--child=%d' % wfd, '--port=%d' % (options.port + j * 3)]
1063 1055 childtmp = os.path.join(HGTMP, 'child%d' % j)
1064 1056 childopts += ['--tmpdir', childtmp]
1065 1057 cmdline = [PYTHON, sys.argv[0]] + opts + childopts + job
1066 1058 vlog(' '.join(cmdline))
1067 1059 fps[os.spawnvp(os.P_NOWAIT, cmdline[0], cmdline)] = os.fdopen(rfd, 'r')
1068 1060 os.close(wfd)
1069 1061 signal.signal(signal.SIGINT, signal.SIG_IGN)
1070 1062 failures = 0
1071 1063 tested, skipped, failed = 0, 0, 0
1072 1064 skips = []
1073 1065 fails = []
1074 1066 while fps:
1075 1067 pid, status = os.wait()
1076 1068 fp = fps.pop(pid)
1077 1069 l = fp.read().splitlines()
1078 1070 try:
1079 1071 test, skip, fail = map(int, l[:3])
1080 1072 except ValueError:
1081 1073 test, skip, fail = 0, 0, 0
1082 1074 split = -fail or len(l)
1083 1075 for s in l[3:split]:
1084 1076 skips.append(s.split(" ", 1))
1085 1077 for s in l[split:]:
1086 1078 fails.append(s.split(" ", 1))
1087 1079 tested += test
1088 1080 skipped += skip
1089 1081 failed += fail
1090 1082 vlog('pid %d exited, status %d' % (pid, status))
1091 1083 failures |= status
1092 1084 print
1093 1085 skipped += len(blacklisted)
1094 1086 if not options.noskips:
1095 1087 for s in skips:
1096 1088 print "Skipped %s: %s" % (s[0], s[1])
1097 1089 for s in blacklisted:
1098 1090 print "Skipped %s: blacklisted" % s
1099 1091 for s in fails:
1100 1092 print "Failed %s: %s" % (s[0], s[1])
1101 1093
1102 1094 _checkhglib("Tested")
1103 1095 print "# Ran %d tests, %d skipped, %d failed." % (
1104 1096 tested, skipped, failed)
1105 1097
1106 1098 if options.anycoverage:
1107 1099 outputcoverage(options)
1108 1100 sys.exit(failures != 0)
1109 1101
1110 1102 results = dict(p=[], f=[], s=[], i=[])
1111 1103 resultslock = threading.Lock()
1112 1104 iolock = threading.Lock()
1113 1105
1114 1106 def runqueue(options, tests, results):
1115 1107 for test in tests:
1116 1108 ret = runone(options, test)
1117 1109 if options.first and ret is not None and not ret:
1118 1110 break
1119 1111
1120 1112 def runtests(options, tests):
1121 1113 global DAEMON_PIDS, HGRCPATH
1122 1114 DAEMON_PIDS = os.environ["DAEMON_PIDS"] = os.path.join(HGTMP, 'daemon.pids')
1123 1115 HGRCPATH = os.environ["HGRCPATH"] = os.path.join(HGTMP, '.hgrc')
1124 1116
1125 1117 try:
1126 1118 if INST:
1127 1119 installhg(options)
1128 1120 _checkhglib("Testing")
1129 1121
1130 1122 if options.restart:
1131 1123 orig = list(tests)
1132 1124 while tests:
1133 1125 if os.path.exists(tests[0] + ".err"):
1134 1126 break
1135 1127 tests.pop(0)
1136 1128 if not tests:
1137 1129 print "running all tests"
1138 1130 tests = orig
1139 1131
1140 1132 runqueue(options, tests, results)
1141 1133
1142 1134 failed = len(results['f'])
1143 1135 tested = len(results['p']) + failed
1144 1136 skipped = len(results['s'])
1145 1137 ignored = len(results['i'])
1146 1138
1147 1139 if options.child:
1148 1140 fp = os.fdopen(options.child, 'w')
1149 1141 fp.write('%d\n%d\n%d\n' % (tested, skipped, failed))
1150 1142 for s in results['s']:
1151 1143 fp.write("%s %s\n" % s)
1152 1144 for s in results['f']:
1153 1145 fp.write("%s %s\n" % s)
1154 1146 fp.close()
1155 1147 else:
1156 1148 print
1157 1149 for s in results['s']:
1158 1150 print "Skipped %s: %s" % s
1159 1151 for s in results['f']:
1160 1152 print "Failed %s: %s" % s
1161 1153 _checkhglib("Tested")
1162 1154 print "# Ran %d tests, %d skipped, %d failed." % (
1163 1155 tested, skipped + ignored, failed)
1164 1156
1165 1157 if options.anycoverage:
1166 1158 outputcoverage(options)
1167 1159 except KeyboardInterrupt:
1168 1160 failed = True
1169 1161 print "\ninterrupted!"
1170 1162
1171 1163 if failed:
1172 1164 sys.exit(1)
1173 1165
1174 1166 def main():
1175 1167 (options, args) = parseargs()
1176 1168 if not options.child:
1177 1169 os.umask(022)
1178 1170
1179 1171 checktools()
1180 1172
1181 1173 if len(args) == 0:
1182 1174 args = os.listdir(".")
1183 1175 args.sort()
1184 1176
1185 1177 tests = args
1186 1178
1187 1179 # Reset some environment variables to well-known values so that
1188 1180 # the tests produce repeatable output.
1189 1181 os.environ['LANG'] = os.environ['LC_ALL'] = os.environ['LANGUAGE'] = 'C'
1190 1182 os.environ['TZ'] = 'GMT'
1191 1183 os.environ["EMAIL"] = "Foo Bar <foo.bar@example.com>"
1192 1184 os.environ['CDPATH'] = ''
1193 1185 os.environ['COLUMNS'] = '80'
1194 1186 os.environ['GREP_OPTIONS'] = ''
1195 1187 os.environ['http_proxy'] = ''
1196 1188 os.environ['no_proxy'] = ''
1197 1189 os.environ['NO_PROXY'] = ''
1198 1190 os.environ['TERM'] = 'xterm'
1199 1191
1200 1192 # unset env related to hooks
1201 1193 for k in os.environ.keys():
1202 1194 if k.startswith('HG_'):
1203 1195 # can't remove on solaris
1204 1196 os.environ[k] = ''
1205 1197 del os.environ[k]
1206 1198 if 'HG' in os.environ:
1207 1199 # can't remove on solaris
1208 1200 os.environ['HG'] = ''
1209 1201 del os.environ['HG']
1210 1202
1211 1203 global TESTDIR, HGTMP, INST, BINDIR, PYTHONDIR, COVERAGE_FILE
1212 1204 TESTDIR = os.environ["TESTDIR"] = os.getcwd()
1213 1205 if options.tmpdir:
1214 1206 options.keep_tmpdir = True
1215 1207 tmpdir = options.tmpdir
1216 1208 if os.path.exists(tmpdir):
1217 1209 # Meaning of tmpdir has changed since 1.3: we used to create
1218 1210 # HGTMP inside tmpdir; now HGTMP is tmpdir. So fail if
1219 1211 # tmpdir already exists.
1220 1212 sys.exit("error: temp dir %r already exists" % tmpdir)
1221 1213
1222 1214 # Automatically removing tmpdir sounds convenient, but could
1223 1215 # really annoy anyone in the habit of using "--tmpdir=/tmp"
1224 1216 # or "--tmpdir=$HOME".
1225 1217 #vlog("# Removing temp dir", tmpdir)
1226 1218 #shutil.rmtree(tmpdir)
1227 1219 os.makedirs(tmpdir)
1228 1220 else:
1229 1221 d = None
1230 1222 if os.name == 'nt':
1231 1223 # without this, we get the default temp dir location, but
1232 1224 # in all lowercase, which causes troubles with paths (issue3490)
1233 1225 d = os.getenv('TMP')
1234 1226 tmpdir = tempfile.mkdtemp('', 'hgtests.', d)
1235 1227 HGTMP = os.environ['HGTMP'] = os.path.realpath(tmpdir)
1236 1228 DAEMON_PIDS = None
1237 1229 HGRCPATH = None
1238 1230
1239 1231 os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
1240 1232 os.environ["HGMERGE"] = "internal:merge"
1241 1233 os.environ["HGUSER"] = "test"
1242 1234 os.environ["HGENCODING"] = "ascii"
1243 1235 os.environ["HGENCODINGMODE"] = "strict"
1244 1236 os.environ["HGPORT"] = str(options.port)
1245 1237 os.environ["HGPORT1"] = str(options.port + 1)
1246 1238 os.environ["HGPORT2"] = str(options.port + 2)
1247 1239
1248 1240 if options.with_hg:
1249 1241 INST = None
1250 1242 BINDIR = os.path.dirname(os.path.realpath(options.with_hg))
1251 1243
1252 1244 # This looks redundant with how Python initializes sys.path from
1253 1245 # the location of the script being executed. Needed because the
1254 1246 # "hg" specified by --with-hg is not the only Python script
1255 1247 # executed in the test suite that needs to import 'mercurial'
1256 1248 # ... which means it's not really redundant at all.
1257 1249 PYTHONDIR = BINDIR
1258 1250 else:
1259 1251 INST = os.path.join(HGTMP, "install")
1260 1252 BINDIR = os.environ["BINDIR"] = os.path.join(INST, "bin")
1261 1253 PYTHONDIR = os.path.join(INST, "lib", "python")
1262 1254
1263 1255 os.environ["BINDIR"] = BINDIR
1264 1256 os.environ["PYTHON"] = PYTHON
1265 1257
1266 1258 if not options.child:
1267 1259 path = [BINDIR] + os.environ["PATH"].split(os.pathsep)
1268 1260 os.environ["PATH"] = os.pathsep.join(path)
1269 1261
1270 1262 # Include TESTDIR in PYTHONPATH so that out-of-tree extensions
1271 1263 # can run .../tests/run-tests.py test-foo where test-foo
1272 1264 # adds an extension to HGRC
1273 1265 pypath = [PYTHONDIR, TESTDIR]
1274 1266 # We have to augment PYTHONPATH, rather than simply replacing
1275 1267 # it, in case external libraries are only available via current
1276 1268 # PYTHONPATH. (In particular, the Subversion bindings on OS X
1277 1269 # are in /opt/subversion.)
1278 1270 oldpypath = os.environ.get(IMPL_PATH)
1279 1271 if oldpypath:
1280 1272 pypath.append(oldpypath)
1281 1273 os.environ[IMPL_PATH] = os.pathsep.join(pypath)
1282 1274
1283 1275 COVERAGE_FILE = os.path.join(TESTDIR, ".coverage")
1284 1276
1285 1277 vlog("# Using TESTDIR", TESTDIR)
1286 1278 vlog("# Using HGTMP", HGTMP)
1287 1279 vlog("# Using PATH", os.environ["PATH"])
1288 1280 vlog("# Using", IMPL_PATH, os.environ[IMPL_PATH])
1289 1281
1290 1282 try:
1291 1283 if len(tests) > 1 and options.jobs > 1:
1292 1284 runchildren(options, tests)
1293 1285 else:
1294 1286 runtests(options, tests)
1295 1287 finally:
1296 1288 time.sleep(.1)
1297 1289 cleanup(options)
1298 1290
1299 1291 if __name__ == '__main__':
1300 1292 main()
General Comments 0
You need to be logged in to leave comments. Login now