##// END OF EJS Templates
run-tests: append PYTHONPATH instead of overwriting it...
Patrick Mezard -
r5251:90919a6f default
parent child Browse files
Show More
@@ -1,464 +1,470 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 #
2 #
3 # run-tests.py - Run a set of tests on Mercurial
3 # run-tests.py - Run a set of tests on Mercurial
4 #
4 #
5 # Copyright 2006 Matt Mackall <mpm@selenic.com>
5 # Copyright 2006 Matt Mackall <mpm@selenic.com>
6 #
6 #
7 # This software may be used and distributed according to the terms
7 # This software may be used and distributed according to the terms
8 # of the GNU General Public License, incorporated herein by reference.
8 # of the GNU General Public License, incorporated herein by reference.
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import optparse
12 import optparse
13 import os
13 import os
14 import popen2
14 import popen2
15 import re
15 import re
16 import shutil
16 import shutil
17 import signal
17 import signal
18 import sys
18 import sys
19 import tempfile
19 import tempfile
20 import time
20 import time
21
21
22 # hghave reserved exit code to skip test
22 # hghave reserved exit code to skip test
23 SKIPPED_STATUS = 80
23 SKIPPED_STATUS = 80
24
24
25 required_tools = ["python", "diff", "grep", "unzip", "gunzip", "bunzip2", "sed"]
25 required_tools = ["python", "diff", "grep", "unzip", "gunzip", "bunzip2", "sed"]
26
26
27 parser = optparse.OptionParser("%prog [options] [tests]")
27 parser = optparse.OptionParser("%prog [options] [tests]")
28 parser.add_option("-v", "--verbose", action="store_true",
28 parser.add_option("-v", "--verbose", action="store_true",
29 help="output verbose messages")
29 help="output verbose messages")
30 parser.add_option("-t", "--timeout", type="int",
30 parser.add_option("-t", "--timeout", type="int",
31 help="kill errant tests after TIMEOUT seconds")
31 help="kill errant tests after TIMEOUT seconds")
32 parser.add_option("-c", "--cover", action="store_true",
32 parser.add_option("-c", "--cover", action="store_true",
33 help="print a test coverage report")
33 help="print a test coverage report")
34 parser.add_option("-s", "--cover_stdlib", action="store_true",
34 parser.add_option("-s", "--cover_stdlib", action="store_true",
35 help="print a test coverage report inc. standard libraries")
35 help="print a test coverage report inc. standard libraries")
36 parser.add_option("-C", "--annotate", action="store_true",
36 parser.add_option("-C", "--annotate", action="store_true",
37 help="output files annotated with coverage")
37 help="output files annotated with coverage")
38 parser.add_option("-r", "--retest", action="store_true",
38 parser.add_option("-r", "--retest", action="store_true",
39 help="retest failed tests")
39 help="retest failed tests")
40 parser.add_option("-f", "--first", action="store_true",
40 parser.add_option("-f", "--first", action="store_true",
41 help="exit on the first test failure")
41 help="exit on the first test failure")
42 parser.add_option("-R", "--restart", action="store_true",
42 parser.add_option("-R", "--restart", action="store_true",
43 help="restart at last error")
43 help="restart at last error")
44 parser.add_option("-i", "--interactive", action="store_true",
44 parser.add_option("-i", "--interactive", action="store_true",
45 help="prompt to accept changed output")
45 help="prompt to accept changed output")
46
46
47 parser.set_defaults(timeout=180)
47 parser.set_defaults(timeout=180)
48 (options, args) = parser.parse_args()
48 (options, args) = parser.parse_args()
49 verbose = options.verbose
49 verbose = options.verbose
50 coverage = options.cover or options.cover_stdlib or options.annotate
50 coverage = options.cover or options.cover_stdlib or options.annotate
51 python = sys.executable
51 python = sys.executable
52
52
53 def vlog(*msg):
53 def vlog(*msg):
54 if verbose:
54 if verbose:
55 for m in msg:
55 for m in msg:
56 print m,
56 print m,
57 print
57 print
58
58
59 def splitnewlines(text):
59 def splitnewlines(text):
60 '''like str.splitlines, but only split on newlines.
60 '''like str.splitlines, but only split on newlines.
61 keep line endings.'''
61 keep line endings.'''
62 i = 0
62 i = 0
63 lines = []
63 lines = []
64 while True:
64 while True:
65 n = text.find('\n', i)
65 n = text.find('\n', i)
66 if n == -1:
66 if n == -1:
67 last = text[i:]
67 last = text[i:]
68 if last:
68 if last:
69 lines.append(last)
69 lines.append(last)
70 return lines
70 return lines
71 lines.append(text[i:n+1])
71 lines.append(text[i:n+1])
72 i = n + 1
72 i = n + 1
73
73
74 def extract_missing_features(lines):
74 def extract_missing_features(lines):
75 '''Extract missing/unknown features log lines as a list'''
75 '''Extract missing/unknown features log lines as a list'''
76 missing = []
76 missing = []
77 for line in lines:
77 for line in lines:
78 if not line.startswith('hghave: '):
78 if not line.startswith('hghave: '):
79 continue
79 continue
80 line = line.splitlines()[0]
80 line = line.splitlines()[0]
81 missing.append(line[8:])
81 missing.append(line[8:])
82
82
83 return missing
83 return missing
84
84
85 def show_diff(expected, output):
85 def show_diff(expected, output):
86 for line in difflib.unified_diff(expected, output,
86 for line in difflib.unified_diff(expected, output,
87 "Expected output", "Test output"):
87 "Expected output", "Test output"):
88 sys.stdout.write(line)
88 sys.stdout.write(line)
89
89
90 def find_program(program):
90 def find_program(program):
91 """Search PATH for a executable program"""
91 """Search PATH for a executable program"""
92 for p in os.environ.get('PATH', os.defpath).split(os.pathsep):
92 for p in os.environ.get('PATH', os.defpath).split(os.pathsep):
93 name = os.path.join(p, program)
93 name = os.path.join(p, program)
94 if os.access(name, os.X_OK):
94 if os.access(name, os.X_OK):
95 return name
95 return name
96 return None
96 return None
97
97
98 def check_required_tools():
98 def check_required_tools():
99 # Before we go any further, check for pre-requisite tools
99 # Before we go any further, check for pre-requisite tools
100 # stuff from coreutils (cat, rm, etc) are not tested
100 # stuff from coreutils (cat, rm, etc) are not tested
101 for p in required_tools:
101 for p in required_tools:
102 if os.name == 'nt':
102 if os.name == 'nt':
103 p += '.exe'
103 p += '.exe'
104 found = find_program(p)
104 found = find_program(p)
105 if found:
105 if found:
106 vlog("# Found prerequisite", p, "at", found)
106 vlog("# Found prerequisite", p, "at", found)
107 else:
107 else:
108 print "WARNING: Did not find prerequisite tool: "+p
108 print "WARNING: Did not find prerequisite tool: "+p
109
109
110 def cleanup_exit():
110 def cleanup_exit():
111 if verbose:
111 if verbose:
112 print "# Cleaning up HGTMP", HGTMP
112 print "# Cleaning up HGTMP", HGTMP
113 shutil.rmtree(HGTMP, True)
113 shutil.rmtree(HGTMP, True)
114
114
115 def use_correct_python():
115 def use_correct_python():
116 # some tests run python interpreter. they must use same
116 # some tests run python interpreter. they must use same
117 # interpreter we use or bad things will happen.
117 # interpreter we use or bad things will happen.
118 exedir, exename = os.path.split(sys.executable)
118 exedir, exename = os.path.split(sys.executable)
119 if exename == 'python':
119 if exename == 'python':
120 path = find_program('python')
120 path = find_program('python')
121 if os.path.dirname(path) == exedir:
121 if os.path.dirname(path) == exedir:
122 return
122 return
123 vlog('# Making python executable in test path use correct Python')
123 vlog('# Making python executable in test path use correct Python')
124 my_python = os.path.join(BINDIR, 'python')
124 my_python = os.path.join(BINDIR, 'python')
125 try:
125 try:
126 os.symlink(sys.executable, my_python)
126 os.symlink(sys.executable, my_python)
127 except AttributeError:
127 except AttributeError:
128 # windows fallback
128 # windows fallback
129 shutil.copyfile(sys.executable, my_python)
129 shutil.copyfile(sys.executable, my_python)
130 shutil.copymode(sys.executable, my_python)
130 shutil.copymode(sys.executable, my_python)
131
131
132 def install_hg():
132 def install_hg():
133 global python
133 global python
134 vlog("# Performing temporary installation of HG")
134 vlog("# Performing temporary installation of HG")
135 installerrs = os.path.join("tests", "install.err")
135 installerrs = os.path.join("tests", "install.err")
136
136
137 os.chdir("..") # Get back to hg root
137 os.chdir("..") # Get back to hg root
138 cmd = ('%s setup.py clean --all'
138 cmd = ('%s setup.py clean --all'
139 ' install --force --home="%s" --install-lib="%s"'
139 ' install --force --home="%s" --install-lib="%s"'
140 ' --install-scripts="%s" >%s 2>&1'
140 ' --install-scripts="%s" >%s 2>&1'
141 % (sys.executable, INST, PYTHONDIR, BINDIR, installerrs))
141 % (sys.executable, INST, PYTHONDIR, BINDIR, installerrs))
142 vlog("# Running", cmd)
142 vlog("# Running", cmd)
143 if os.system(cmd) == 0:
143 if os.system(cmd) == 0:
144 if not verbose:
144 if not verbose:
145 os.remove(installerrs)
145 os.remove(installerrs)
146 else:
146 else:
147 f = open(installerrs)
147 f = open(installerrs)
148 for line in f:
148 for line in f:
149 print line,
149 print line,
150 f.close()
150 f.close()
151 sys.exit(1)
151 sys.exit(1)
152 os.chdir(TESTDIR)
152 os.chdir(TESTDIR)
153
153
154 os.environ["PATH"] = "%s%s%s" % (BINDIR, os.pathsep, os.environ["PATH"])
154 os.environ["PATH"] = "%s%s%s" % (BINDIR, os.pathsep, os.environ["PATH"])
155 os.environ["PYTHONPATH"] = PYTHONDIR
155
156 pythonpath = os.environ.get("PYTHONPATH")
157 if pythonpath:
158 pythonpath = PYTHONDIR + os.pathsep + pythonpath
159 else:
160 pythonpath = PYTHONDIR
161 os.environ["PYTHONPATH"] = pythonpath
156
162
157 use_correct_python()
163 use_correct_python()
158
164
159 if coverage:
165 if coverage:
160 vlog("# Installing coverage wrapper")
166 vlog("# Installing coverage wrapper")
161 os.environ['COVERAGE_FILE'] = COVERAGE_FILE
167 os.environ['COVERAGE_FILE'] = COVERAGE_FILE
162 if os.path.exists(COVERAGE_FILE):
168 if os.path.exists(COVERAGE_FILE):
163 os.unlink(COVERAGE_FILE)
169 os.unlink(COVERAGE_FILE)
164 # Create a wrapper script to invoke hg via coverage.py
170 # Create a wrapper script to invoke hg via coverage.py
165 os.rename(os.path.join(BINDIR, "hg"), os.path.join(BINDIR, "_hg.py"))
171 os.rename(os.path.join(BINDIR, "hg"), os.path.join(BINDIR, "_hg.py"))
166 f = open(os.path.join(BINDIR, 'hg'), 'w')
172 f = open(os.path.join(BINDIR, 'hg'), 'w')
167 f.write('#!' + sys.executable + '\n')
173 f.write('#!' + sys.executable + '\n')
168 f.write('import sys, os; os.execv(sys.executable, [sys.executable, '
174 f.write('import sys, os; os.execv(sys.executable, [sys.executable, '
169 '"%s", "-x", "%s"] + sys.argv[1:])\n' %
175 '"%s", "-x", "%s"] + sys.argv[1:])\n' %
170 (os.path.join(TESTDIR, 'coverage.py'),
176 (os.path.join(TESTDIR, 'coverage.py'),
171 os.path.join(BINDIR, '_hg.py')))
177 os.path.join(BINDIR, '_hg.py')))
172 f.close()
178 f.close()
173 os.chmod(os.path.join(BINDIR, 'hg'), 0700)
179 os.chmod(os.path.join(BINDIR, 'hg'), 0700)
174 python = '"%s" "%s" -x' % (sys.executable,
180 python = '"%s" "%s" -x' % (sys.executable,
175 os.path.join(TESTDIR,'coverage.py'))
181 os.path.join(TESTDIR,'coverage.py'))
176
182
177 def output_coverage():
183 def output_coverage():
178 vlog("# Producing coverage report")
184 vlog("# Producing coverage report")
179 omit = [BINDIR, TESTDIR, PYTHONDIR]
185 omit = [BINDIR, TESTDIR, PYTHONDIR]
180 if not options.cover_stdlib:
186 if not options.cover_stdlib:
181 # Exclude as system paths (ignoring empty strings seen on win)
187 # Exclude as system paths (ignoring empty strings seen on win)
182 omit += [x for x in sys.path if x != '']
188 omit += [x for x in sys.path if x != '']
183 omit = ','.join(omit)
189 omit = ','.join(omit)
184 os.chdir(PYTHONDIR)
190 os.chdir(PYTHONDIR)
185 cmd = '"%s" "%s" -i -r "--omit=%s"' % (
191 cmd = '"%s" "%s" -i -r "--omit=%s"' % (
186 sys.executable, os.path.join(TESTDIR, 'coverage.py'), omit)
192 sys.executable, os.path.join(TESTDIR, 'coverage.py'), omit)
187 vlog("# Running: "+cmd)
193 vlog("# Running: "+cmd)
188 os.system(cmd)
194 os.system(cmd)
189 if options.annotate:
195 if options.annotate:
190 adir = os.path.join(TESTDIR, 'annotated')
196 adir = os.path.join(TESTDIR, 'annotated')
191 if not os.path.isdir(adir):
197 if not os.path.isdir(adir):
192 os.mkdir(adir)
198 os.mkdir(adir)
193 cmd = '"%s" "%s" -i -a "--directory=%s" "--omit=%s"' % (
199 cmd = '"%s" "%s" -i -a "--directory=%s" "--omit=%s"' % (
194 sys.executable, os.path.join(TESTDIR, 'coverage.py'),
200 sys.executable, os.path.join(TESTDIR, 'coverage.py'),
195 adir, omit)
201 adir, omit)
196 vlog("# Running: "+cmd)
202 vlog("# Running: "+cmd)
197 os.system(cmd)
203 os.system(cmd)
198
204
199 class Timeout(Exception):
205 class Timeout(Exception):
200 pass
206 pass
201
207
202 def alarmed(signum, frame):
208 def alarmed(signum, frame):
203 raise Timeout
209 raise Timeout
204
210
205 def run(cmd):
211 def run(cmd):
206 """Run command in a sub-process, capturing the output (stdout and stderr).
212 """Run command in a sub-process, capturing the output (stdout and stderr).
207 Return the exist code, and output."""
213 Return the exist code, and output."""
208 # TODO: Use subprocess.Popen if we're running on Python 2.4
214 # TODO: Use subprocess.Popen if we're running on Python 2.4
209 if os.name == 'nt':
215 if os.name == 'nt':
210 tochild, fromchild = os.popen4(cmd)
216 tochild, fromchild = os.popen4(cmd)
211 tochild.close()
217 tochild.close()
212 output = fromchild.read()
218 output = fromchild.read()
213 ret = fromchild.close()
219 ret = fromchild.close()
214 if ret == None:
220 if ret == None:
215 ret = 0
221 ret = 0
216 else:
222 else:
217 proc = popen2.Popen4(cmd)
223 proc = popen2.Popen4(cmd)
218 try:
224 try:
219 output = ''
225 output = ''
220 proc.tochild.close()
226 proc.tochild.close()
221 output = proc.fromchild.read()
227 output = proc.fromchild.read()
222 ret = proc.wait()
228 ret = proc.wait()
223 if os.WIFEXITED(ret):
229 if os.WIFEXITED(ret):
224 ret = os.WEXITSTATUS(ret)
230 ret = os.WEXITSTATUS(ret)
225 except Timeout:
231 except Timeout:
226 vlog('# Process %d timed out - killing it' % proc.pid)
232 vlog('# Process %d timed out - killing it' % proc.pid)
227 os.kill(proc.pid, signal.SIGTERM)
233 os.kill(proc.pid, signal.SIGTERM)
228 ret = proc.wait()
234 ret = proc.wait()
229 if ret == 0:
235 if ret == 0:
230 ret = signal.SIGTERM << 8
236 ret = signal.SIGTERM << 8
231 output += ("\n### Abort: timeout after %d seconds.\n"
237 output += ("\n### Abort: timeout after %d seconds.\n"
232 % options.timeout)
238 % options.timeout)
233 return ret, splitnewlines(output)
239 return ret, splitnewlines(output)
234
240
235 def run_one(test):
241 def run_one(test):
236 '''tristate output:
242 '''tristate output:
237 None -> skipped
243 None -> skipped
238 True -> passed
244 True -> passed
239 False -> failed'''
245 False -> failed'''
240
246
241 vlog("# Test", test)
247 vlog("# Test", test)
242 if not verbose:
248 if not verbose:
243 sys.stdout.write('.')
249 sys.stdout.write('.')
244 sys.stdout.flush()
250 sys.stdout.flush()
245
251
246 # create a fresh hgrc
252 # create a fresh hgrc
247 hgrc = file(HGRCPATH, 'w+')
253 hgrc = file(HGRCPATH, 'w+')
248 hgrc.write('[ui]\n')
254 hgrc.write('[ui]\n')
249 hgrc.write('slash = True\n')
255 hgrc.write('slash = True\n')
250 hgrc.close()
256 hgrc.close()
251
257
252 err = os.path.join(TESTDIR, test+".err")
258 err = os.path.join(TESTDIR, test+".err")
253 ref = os.path.join(TESTDIR, test+".out")
259 ref = os.path.join(TESTDIR, test+".out")
254 testpath = os.path.join(TESTDIR, test)
260 testpath = os.path.join(TESTDIR, test)
255
261
256 if os.path.exists(err):
262 if os.path.exists(err):
257 os.remove(err) # Remove any previous output files
263 os.remove(err) # Remove any previous output files
258
264
259 # Make a tmp subdirectory to work in
265 # Make a tmp subdirectory to work in
260 tmpd = os.path.join(HGTMP, test)
266 tmpd = os.path.join(HGTMP, test)
261 os.mkdir(tmpd)
267 os.mkdir(tmpd)
262 os.chdir(tmpd)
268 os.chdir(tmpd)
263
269
264 try:
270 try:
265 tf = open(testpath)
271 tf = open(testpath)
266 firstline = tf.readline().rstrip()
272 firstline = tf.readline().rstrip()
267 tf.close()
273 tf.close()
268 except:
274 except:
269 firstline = ''
275 firstline = ''
270 lctest = test.lower()
276 lctest = test.lower()
271
277
272 if lctest.endswith('.py') or firstline == '#!/usr/bin/env python':
278 if lctest.endswith('.py') or firstline == '#!/usr/bin/env python':
273 cmd = '%s "%s"' % (python, testpath)
279 cmd = '%s "%s"' % (python, testpath)
274 elif lctest.endswith('.bat'):
280 elif lctest.endswith('.bat'):
275 # do not run batch scripts on non-windows
281 # do not run batch scripts on non-windows
276 if os.name != 'nt':
282 if os.name != 'nt':
277 print '\nSkipping %s: batch script' % test
283 print '\nSkipping %s: batch script' % test
278 return None
284 return None
279 # To reliably get the error code from batch files on WinXP,
285 # To reliably get the error code from batch files on WinXP,
280 # the "cmd /c call" prefix is needed. Grrr
286 # the "cmd /c call" prefix is needed. Grrr
281 cmd = 'cmd /c call "%s"' % testpath
287 cmd = 'cmd /c call "%s"' % testpath
282 else:
288 else:
283 # do not run shell scripts on windows
289 # do not run shell scripts on windows
284 if os.name == 'nt':
290 if os.name == 'nt':
285 print '\nSkipping %s: shell script' % test
291 print '\nSkipping %s: shell script' % test
286 return None
292 return None
287 # do not try to run non-executable programs
293 # do not try to run non-executable programs
288 if not os.access(testpath, os.X_OK):
294 if not os.access(testpath, os.X_OK):
289 print '\nSkipping %s: not executable' % test
295 print '\nSkipping %s: not executable' % test
290 return None
296 return None
291 cmd = '"%s"' % testpath
297 cmd = '"%s"' % testpath
292
298
293 if options.timeout > 0:
299 if options.timeout > 0:
294 signal.alarm(options.timeout)
300 signal.alarm(options.timeout)
295
301
296 vlog("# Running", cmd)
302 vlog("# Running", cmd)
297 ret, out = run(cmd)
303 ret, out = run(cmd)
298 vlog("# Ret was:", ret)
304 vlog("# Ret was:", ret)
299
305
300 if options.timeout > 0:
306 if options.timeout > 0:
301 signal.alarm(0)
307 signal.alarm(0)
302
308
303 skipped = (ret == SKIPPED_STATUS)
309 skipped = (ret == SKIPPED_STATUS)
304 diffret = 0
310 diffret = 0
305 # If reference output file exists, check test output against it
311 # If reference output file exists, check test output against it
306 if os.path.exists(ref):
312 if os.path.exists(ref):
307 f = open(ref, "r")
313 f = open(ref, "r")
308 ref_out = splitnewlines(f.read())
314 ref_out = splitnewlines(f.read())
309 f.close()
315 f.close()
310 else:
316 else:
311 ref_out = []
317 ref_out = []
312 if not skipped and out != ref_out:
318 if not skipped and out != ref_out:
313 diffret = 1
319 diffret = 1
314 print "\nERROR: %s output changed" % (test)
320 print "\nERROR: %s output changed" % (test)
315 show_diff(ref_out, out)
321 show_diff(ref_out, out)
316 if skipped:
322 if skipped:
317 missing = extract_missing_features(out)
323 missing = extract_missing_features(out)
318 if not missing:
324 if not missing:
319 missing = ['irrelevant']
325 missing = ['irrelevant']
320 print '\nSkipping %s: %s' % (test, missing[-1])
326 print '\nSkipping %s: %s' % (test, missing[-1])
321 elif ret:
327 elif ret:
322 print "\nERROR: %s failed with error code %d" % (test, ret)
328 print "\nERROR: %s failed with error code %d" % (test, ret)
323 elif diffret:
329 elif diffret:
324 ret = diffret
330 ret = diffret
325
331
326 if ret != 0 and not skipped:
332 if ret != 0 and not skipped:
327 # Save errors to a file for diagnosis
333 # Save errors to a file for diagnosis
328 f = open(err, "wb")
334 f = open(err, "wb")
329 for line in out:
335 for line in out:
330 f.write(line)
336 f.write(line)
331 f.close()
337 f.close()
332
338
333 # Kill off any leftover daemon processes
339 # Kill off any leftover daemon processes
334 try:
340 try:
335 fp = file(DAEMON_PIDS)
341 fp = file(DAEMON_PIDS)
336 for line in fp:
342 for line in fp:
337 try:
343 try:
338 pid = int(line)
344 pid = int(line)
339 except ValueError:
345 except ValueError:
340 continue
346 continue
341 try:
347 try:
342 os.kill(pid, 0)
348 os.kill(pid, 0)
343 vlog('# Killing daemon process %d' % pid)
349 vlog('# Killing daemon process %d' % pid)
344 os.kill(pid, signal.SIGTERM)
350 os.kill(pid, signal.SIGTERM)
345 time.sleep(0.25)
351 time.sleep(0.25)
346 os.kill(pid, 0)
352 os.kill(pid, 0)
347 vlog('# Daemon process %d is stuck - really killing it' % pid)
353 vlog('# Daemon process %d is stuck - really killing it' % pid)
348 os.kill(pid, signal.SIGKILL)
354 os.kill(pid, signal.SIGKILL)
349 except OSError, err:
355 except OSError, err:
350 if err.errno != errno.ESRCH:
356 if err.errno != errno.ESRCH:
351 raise
357 raise
352 fp.close()
358 fp.close()
353 os.unlink(DAEMON_PIDS)
359 os.unlink(DAEMON_PIDS)
354 except IOError:
360 except IOError:
355 pass
361 pass
356
362
357 os.chdir(TESTDIR)
363 os.chdir(TESTDIR)
358 shutil.rmtree(tmpd, True)
364 shutil.rmtree(tmpd, True)
359 if skipped:
365 if skipped:
360 return None
366 return None
361 return ret == 0
367 return ret == 0
362
368
363
369
364 os.umask(022)
370 os.umask(022)
365
371
366 check_required_tools()
372 check_required_tools()
367
373
368 # Reset some environment variables to well-known values so that
374 # Reset some environment variables to well-known values so that
369 # the tests produce repeatable output.
375 # the tests produce repeatable output.
370 os.environ['LANG'] = os.environ['LC_ALL'] = 'C'
376 os.environ['LANG'] = os.environ['LC_ALL'] = 'C'
371 os.environ['TZ'] = 'GMT'
377 os.environ['TZ'] = 'GMT'
372
378
373 TESTDIR = os.environ["TESTDIR"] = os.getcwd()
379 TESTDIR = os.environ["TESTDIR"] = os.getcwd()
374 HGTMP = os.environ["HGTMP"] = tempfile.mkdtemp("", "hgtests.")
380 HGTMP = os.environ["HGTMP"] = tempfile.mkdtemp("", "hgtests.")
375 DAEMON_PIDS = os.environ["DAEMON_PIDS"] = os.path.join(HGTMP, 'daemon.pids')
381 DAEMON_PIDS = os.environ["DAEMON_PIDS"] = os.path.join(HGTMP, 'daemon.pids')
376 HGRCPATH = os.environ["HGRCPATH"] = os.path.join(HGTMP, '.hgrc')
382 HGRCPATH = os.environ["HGRCPATH"] = os.path.join(HGTMP, '.hgrc')
377
383
378 os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
384 os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
379 os.environ["HGMERGE"] = ('python "%s" -L my -L other'
385 os.environ["HGMERGE"] = ('python "%s" -L my -L other'
380 % os.path.join(TESTDIR, os.path.pardir, 'contrib',
386 % os.path.join(TESTDIR, os.path.pardir, 'contrib',
381 'simplemerge'))
387 'simplemerge'))
382 os.environ["HGUSER"] = "test"
388 os.environ["HGUSER"] = "test"
383 os.environ["HGENCODING"] = "ascii"
389 os.environ["HGENCODING"] = "ascii"
384 os.environ["HGENCODINGMODE"] = "strict"
390 os.environ["HGENCODINGMODE"] = "strict"
385
391
386 vlog("# Using TESTDIR", TESTDIR)
392 vlog("# Using TESTDIR", TESTDIR)
387 vlog("# Using HGTMP", HGTMP)
393 vlog("# Using HGTMP", HGTMP)
388
394
389 INST = os.path.join(HGTMP, "install")
395 INST = os.path.join(HGTMP, "install")
390 BINDIR = os.path.join(INST, "bin")
396 BINDIR = os.path.join(INST, "bin")
391 PYTHONDIR = os.path.join(INST, "lib", "python")
397 PYTHONDIR = os.path.join(INST, "lib", "python")
392 COVERAGE_FILE = os.path.join(TESTDIR, ".coverage")
398 COVERAGE_FILE = os.path.join(TESTDIR, ".coverage")
393
399
394 try:
400 try:
395 try:
401 try:
396 install_hg()
402 install_hg()
397
403
398 if options.timeout > 0:
404 if options.timeout > 0:
399 try:
405 try:
400 signal.signal(signal.SIGALRM, alarmed)
406 signal.signal(signal.SIGALRM, alarmed)
401 vlog('# Running tests with %d-second timeout' %
407 vlog('# Running tests with %d-second timeout' %
402 options.timeout)
408 options.timeout)
403 except AttributeError:
409 except AttributeError:
404 print 'WARNING: cannot run tests with timeouts'
410 print 'WARNING: cannot run tests with timeouts'
405 options.timeout = 0
411 options.timeout = 0
406
412
407 tested = 0
413 tested = 0
408 failed = 0
414 failed = 0
409 skipped = 0
415 skipped = 0
410
416
411 if len(args) == 0:
417 if len(args) == 0:
412 args = os.listdir(".")
418 args = os.listdir(".")
413 args.sort()
419 args.sort()
414
420
415
421
416 tests = []
422 tests = []
417 for test in args:
423 for test in args:
418 if (test.startswith("test-") and '~' not in test and
424 if (test.startswith("test-") and '~' not in test and
419 ('.' not in test or test.endswith('.py') or
425 ('.' not in test or test.endswith('.py') or
420 test.endswith('.bat'))):
426 test.endswith('.bat'))):
421 tests.append(test)
427 tests.append(test)
422
428
423 if options.restart:
429 if options.restart:
424 orig = list(tests)
430 orig = list(tests)
425 while tests:
431 while tests:
426 if os.path.exists(tests[0] + ".err"):
432 if os.path.exists(tests[0] + ".err"):
427 break
433 break
428 tests.pop(0)
434 tests.pop(0)
429 if not tests:
435 if not tests:
430 print "running all tests"
436 print "running all tests"
431 tests = orig
437 tests = orig
432
438
433 for test in tests:
439 for test in tests:
434 if options.retest and not os.path.exists(test + ".err"):
440 if options.retest and not os.path.exists(test + ".err"):
435 skipped += 1
441 skipped += 1
436 continue
442 continue
437 ret = run_one(test)
443 ret = run_one(test)
438 if ret is None:
444 if ret is None:
439 skipped += 1
445 skipped += 1
440 elif not ret:
446 elif not ret:
441 if options.interactive:
447 if options.interactive:
442 print "Accept this change? [n] ",
448 print "Accept this change? [n] ",
443 answer = sys.stdin.readline().strip()
449 answer = sys.stdin.readline().strip()
444 if answer.lower() in "y yes".split():
450 if answer.lower() in "y yes".split():
445 os.rename(test + ".err", test + ".out")
451 os.rename(test + ".err", test + ".out")
446 tested += 1
452 tested += 1
447 continue
453 continue
448 failed += 1
454 failed += 1
449 if options.first:
455 if options.first:
450 break
456 break
451 tested += 1
457 tested += 1
452
458
453 print "\n# Ran %d tests, %d skipped, %d failed." % (tested, skipped,
459 print "\n# Ran %d tests, %d skipped, %d failed." % (tested, skipped,
454 failed)
460 failed)
455 if coverage:
461 if coverage:
456 output_coverage()
462 output_coverage()
457 except KeyboardInterrupt:
463 except KeyboardInterrupt:
458 failed = True
464 failed = True
459 print "\ninterrupted!"
465 print "\ninterrupted!"
460 finally:
466 finally:
461 cleanup_exit()
467 cleanup_exit()
462
468
463 if failed:
469 if failed:
464 sys.exit(1)
470 sys.exit(1)
General Comments 0
You need to be logged in to leave comments. Login now