##// END OF EJS Templates
Make run-tests.py work when invoked outside of tests....
Brendan Cully -
r5267:b817d17c default
parent child Browse files
Show More
@@ -1,470 +1,471 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 # Run installer in hg root
138 os.chdir(os.path.join(os.path.dirname(sys.argv[0]), '..'))
138 cmd = ('%s setup.py clean --all'
139 cmd = ('%s setup.py clean --all'
139 ' install --force --home="%s" --install-lib="%s"'
140 ' install --force --home="%s" --install-lib="%s"'
140 ' --install-scripts="%s" >%s 2>&1'
141 ' --install-scripts="%s" >%s 2>&1'
141 % (sys.executable, INST, PYTHONDIR, BINDIR, installerrs))
142 % (sys.executable, INST, PYTHONDIR, BINDIR, installerrs))
142 vlog("# Running", cmd)
143 vlog("# Running", cmd)
143 if os.system(cmd) == 0:
144 if os.system(cmd) == 0:
144 if not verbose:
145 if not verbose:
145 os.remove(installerrs)
146 os.remove(installerrs)
146 else:
147 else:
147 f = open(installerrs)
148 f = open(installerrs)
148 for line in f:
149 for line in f:
149 print line,
150 print line,
150 f.close()
151 f.close()
151 sys.exit(1)
152 sys.exit(1)
152 os.chdir(TESTDIR)
153 os.chdir(TESTDIR)
153
154
154 os.environ["PATH"] = "%s%s%s" % (BINDIR, os.pathsep, os.environ["PATH"])
155 os.environ["PATH"] = "%s%s%s" % (BINDIR, os.pathsep, os.environ["PATH"])
155
156
156 pythonpath = os.environ.get("PYTHONPATH")
157 pythonpath = os.environ.get("PYTHONPATH")
157 if pythonpath:
158 if pythonpath:
158 pythonpath = PYTHONDIR + os.pathsep + pythonpath
159 pythonpath = PYTHONDIR + os.pathsep + pythonpath
159 else:
160 else:
160 pythonpath = PYTHONDIR
161 pythonpath = PYTHONDIR
161 os.environ["PYTHONPATH"] = pythonpath
162 os.environ["PYTHONPATH"] = pythonpath
162
163
163 use_correct_python()
164 use_correct_python()
164
165
165 if coverage:
166 if coverage:
166 vlog("# Installing coverage wrapper")
167 vlog("# Installing coverage wrapper")
167 os.environ['COVERAGE_FILE'] = COVERAGE_FILE
168 os.environ['COVERAGE_FILE'] = COVERAGE_FILE
168 if os.path.exists(COVERAGE_FILE):
169 if os.path.exists(COVERAGE_FILE):
169 os.unlink(COVERAGE_FILE)
170 os.unlink(COVERAGE_FILE)
170 # Create a wrapper script to invoke hg via coverage.py
171 # Create a wrapper script to invoke hg via coverage.py
171 os.rename(os.path.join(BINDIR, "hg"), os.path.join(BINDIR, "_hg.py"))
172 os.rename(os.path.join(BINDIR, "hg"), os.path.join(BINDIR, "_hg.py"))
172 f = open(os.path.join(BINDIR, 'hg'), 'w')
173 f = open(os.path.join(BINDIR, 'hg'), 'w')
173 f.write('#!' + sys.executable + '\n')
174 f.write('#!' + sys.executable + '\n')
174 f.write('import sys, os; os.execv(sys.executable, [sys.executable, '
175 f.write('import sys, os; os.execv(sys.executable, [sys.executable, '
175 '"%s", "-x", "%s"] + sys.argv[1:])\n' %
176 '"%s", "-x", "%s"] + sys.argv[1:])\n' %
176 (os.path.join(TESTDIR, 'coverage.py'),
177 (os.path.join(TESTDIR, 'coverage.py'),
177 os.path.join(BINDIR, '_hg.py')))
178 os.path.join(BINDIR, '_hg.py')))
178 f.close()
179 f.close()
179 os.chmod(os.path.join(BINDIR, 'hg'), 0700)
180 os.chmod(os.path.join(BINDIR, 'hg'), 0700)
180 python = '"%s" "%s" -x' % (sys.executable,
181 python = '"%s" "%s" -x' % (sys.executable,
181 os.path.join(TESTDIR,'coverage.py'))
182 os.path.join(TESTDIR,'coverage.py'))
182
183
183 def output_coverage():
184 def output_coverage():
184 vlog("# Producing coverage report")
185 vlog("# Producing coverage report")
185 omit = [BINDIR, TESTDIR, PYTHONDIR]
186 omit = [BINDIR, TESTDIR, PYTHONDIR]
186 if not options.cover_stdlib:
187 if not options.cover_stdlib:
187 # Exclude as system paths (ignoring empty strings seen on win)
188 # Exclude as system paths (ignoring empty strings seen on win)
188 omit += [x for x in sys.path if x != '']
189 omit += [x for x in sys.path if x != '']
189 omit = ','.join(omit)
190 omit = ','.join(omit)
190 os.chdir(PYTHONDIR)
191 os.chdir(PYTHONDIR)
191 cmd = '"%s" "%s" -i -r "--omit=%s"' % (
192 cmd = '"%s" "%s" -i -r "--omit=%s"' % (
192 sys.executable, os.path.join(TESTDIR, 'coverage.py'), omit)
193 sys.executable, os.path.join(TESTDIR, 'coverage.py'), omit)
193 vlog("# Running: "+cmd)
194 vlog("# Running: "+cmd)
194 os.system(cmd)
195 os.system(cmd)
195 if options.annotate:
196 if options.annotate:
196 adir = os.path.join(TESTDIR, 'annotated')
197 adir = os.path.join(TESTDIR, 'annotated')
197 if not os.path.isdir(adir):
198 if not os.path.isdir(adir):
198 os.mkdir(adir)
199 os.mkdir(adir)
199 cmd = '"%s" "%s" -i -a "--directory=%s" "--omit=%s"' % (
200 cmd = '"%s" "%s" -i -a "--directory=%s" "--omit=%s"' % (
200 sys.executable, os.path.join(TESTDIR, 'coverage.py'),
201 sys.executable, os.path.join(TESTDIR, 'coverage.py'),
201 adir, omit)
202 adir, omit)
202 vlog("# Running: "+cmd)
203 vlog("# Running: "+cmd)
203 os.system(cmd)
204 os.system(cmd)
204
205
205 class Timeout(Exception):
206 class Timeout(Exception):
206 pass
207 pass
207
208
208 def alarmed(signum, frame):
209 def alarmed(signum, frame):
209 raise Timeout
210 raise Timeout
210
211
211 def run(cmd):
212 def run(cmd):
212 """Run command in a sub-process, capturing the output (stdout and stderr).
213 """Run command in a sub-process, capturing the output (stdout and stderr).
213 Return the exist code, and output."""
214 Return the exist code, and output."""
214 # TODO: Use subprocess.Popen if we're running on Python 2.4
215 # TODO: Use subprocess.Popen if we're running on Python 2.4
215 if os.name == 'nt':
216 if os.name == 'nt':
216 tochild, fromchild = os.popen4(cmd)
217 tochild, fromchild = os.popen4(cmd)
217 tochild.close()
218 tochild.close()
218 output = fromchild.read()
219 output = fromchild.read()
219 ret = fromchild.close()
220 ret = fromchild.close()
220 if ret == None:
221 if ret == None:
221 ret = 0
222 ret = 0
222 else:
223 else:
223 proc = popen2.Popen4(cmd)
224 proc = popen2.Popen4(cmd)
224 try:
225 try:
225 output = ''
226 output = ''
226 proc.tochild.close()
227 proc.tochild.close()
227 output = proc.fromchild.read()
228 output = proc.fromchild.read()
228 ret = proc.wait()
229 ret = proc.wait()
229 if os.WIFEXITED(ret):
230 if os.WIFEXITED(ret):
230 ret = os.WEXITSTATUS(ret)
231 ret = os.WEXITSTATUS(ret)
231 except Timeout:
232 except Timeout:
232 vlog('# Process %d timed out - killing it' % proc.pid)
233 vlog('# Process %d timed out - killing it' % proc.pid)
233 os.kill(proc.pid, signal.SIGTERM)
234 os.kill(proc.pid, signal.SIGTERM)
234 ret = proc.wait()
235 ret = proc.wait()
235 if ret == 0:
236 if ret == 0:
236 ret = signal.SIGTERM << 8
237 ret = signal.SIGTERM << 8
237 output += ("\n### Abort: timeout after %d seconds.\n"
238 output += ("\n### Abort: timeout after %d seconds.\n"
238 % options.timeout)
239 % options.timeout)
239 return ret, splitnewlines(output)
240 return ret, splitnewlines(output)
240
241
241 def run_one(test):
242 def run_one(test):
242 '''tristate output:
243 '''tristate output:
243 None -> skipped
244 None -> skipped
244 True -> passed
245 True -> passed
245 False -> failed'''
246 False -> failed'''
246
247
247 vlog("# Test", test)
248 vlog("# Test", test)
248 if not verbose:
249 if not verbose:
249 sys.stdout.write('.')
250 sys.stdout.write('.')
250 sys.stdout.flush()
251 sys.stdout.flush()
251
252
252 # create a fresh hgrc
253 # create a fresh hgrc
253 hgrc = file(HGRCPATH, 'w+')
254 hgrc = file(HGRCPATH, 'w+')
254 hgrc.write('[ui]\n')
255 hgrc.write('[ui]\n')
255 hgrc.write('slash = True\n')
256 hgrc.write('slash = True\n')
256 hgrc.close()
257 hgrc.close()
257
258
258 err = os.path.join(TESTDIR, test+".err")
259 err = os.path.join(TESTDIR, test+".err")
259 ref = os.path.join(TESTDIR, test+".out")
260 ref = os.path.join(TESTDIR, test+".out")
260 testpath = os.path.join(TESTDIR, test)
261 testpath = os.path.join(TESTDIR, test)
261
262
262 if os.path.exists(err):
263 if os.path.exists(err):
263 os.remove(err) # Remove any previous output files
264 os.remove(err) # Remove any previous output files
264
265
265 # Make a tmp subdirectory to work in
266 # Make a tmp subdirectory to work in
266 tmpd = os.path.join(HGTMP, test)
267 tmpd = os.path.join(HGTMP, test)
267 os.mkdir(tmpd)
268 os.mkdir(tmpd)
268 os.chdir(tmpd)
269 os.chdir(tmpd)
269
270
270 try:
271 try:
271 tf = open(testpath)
272 tf = open(testpath)
272 firstline = tf.readline().rstrip()
273 firstline = tf.readline().rstrip()
273 tf.close()
274 tf.close()
274 except:
275 except:
275 firstline = ''
276 firstline = ''
276 lctest = test.lower()
277 lctest = test.lower()
277
278
278 if lctest.endswith('.py') or firstline == '#!/usr/bin/env python':
279 if lctest.endswith('.py') or firstline == '#!/usr/bin/env python':
279 cmd = '%s "%s"' % (python, testpath)
280 cmd = '%s "%s"' % (python, testpath)
280 elif lctest.endswith('.bat'):
281 elif lctest.endswith('.bat'):
281 # do not run batch scripts on non-windows
282 # do not run batch scripts on non-windows
282 if os.name != 'nt':
283 if os.name != 'nt':
283 print '\nSkipping %s: batch script' % test
284 print '\nSkipping %s: batch script' % test
284 return None
285 return None
285 # To reliably get the error code from batch files on WinXP,
286 # To reliably get the error code from batch files on WinXP,
286 # the "cmd /c call" prefix is needed. Grrr
287 # the "cmd /c call" prefix is needed. Grrr
287 cmd = 'cmd /c call "%s"' % testpath
288 cmd = 'cmd /c call "%s"' % testpath
288 else:
289 else:
289 # do not run shell scripts on windows
290 # do not run shell scripts on windows
290 if os.name == 'nt':
291 if os.name == 'nt':
291 print '\nSkipping %s: shell script' % test
292 print '\nSkipping %s: shell script' % test
292 return None
293 return None
293 # do not try to run non-executable programs
294 # do not try to run non-executable programs
294 if not os.access(testpath, os.X_OK):
295 if not os.access(testpath, os.X_OK):
295 print '\nSkipping %s: not executable' % test
296 print '\nSkipping %s: not executable' % test
296 return None
297 return None
297 cmd = '"%s"' % testpath
298 cmd = '"%s"' % testpath
298
299
299 if options.timeout > 0:
300 if options.timeout > 0:
300 signal.alarm(options.timeout)
301 signal.alarm(options.timeout)
301
302
302 vlog("# Running", cmd)
303 vlog("# Running", cmd)
303 ret, out = run(cmd)
304 ret, out = run(cmd)
304 vlog("# Ret was:", ret)
305 vlog("# Ret was:", ret)
305
306
306 if options.timeout > 0:
307 if options.timeout > 0:
307 signal.alarm(0)
308 signal.alarm(0)
308
309
309 skipped = (ret == SKIPPED_STATUS)
310 skipped = (ret == SKIPPED_STATUS)
310 diffret = 0
311 diffret = 0
311 # If reference output file exists, check test output against it
312 # If reference output file exists, check test output against it
312 if os.path.exists(ref):
313 if os.path.exists(ref):
313 f = open(ref, "r")
314 f = open(ref, "r")
314 ref_out = splitnewlines(f.read())
315 ref_out = splitnewlines(f.read())
315 f.close()
316 f.close()
316 else:
317 else:
317 ref_out = []
318 ref_out = []
318 if not skipped and out != ref_out:
319 if not skipped and out != ref_out:
319 diffret = 1
320 diffret = 1
320 print "\nERROR: %s output changed" % (test)
321 print "\nERROR: %s output changed" % (test)
321 show_diff(ref_out, out)
322 show_diff(ref_out, out)
322 if skipped:
323 if skipped:
323 missing = extract_missing_features(out)
324 missing = extract_missing_features(out)
324 if not missing:
325 if not missing:
325 missing = ['irrelevant']
326 missing = ['irrelevant']
326 print '\nSkipping %s: %s' % (test, missing[-1])
327 print '\nSkipping %s: %s' % (test, missing[-1])
327 elif ret:
328 elif ret:
328 print "\nERROR: %s failed with error code %d" % (test, ret)
329 print "\nERROR: %s failed with error code %d" % (test, ret)
329 elif diffret:
330 elif diffret:
330 ret = diffret
331 ret = diffret
331
332
332 if ret != 0 and not skipped:
333 if ret != 0 and not skipped:
333 # Save errors to a file for diagnosis
334 # Save errors to a file for diagnosis
334 f = open(err, "wb")
335 f = open(err, "wb")
335 for line in out:
336 for line in out:
336 f.write(line)
337 f.write(line)
337 f.close()
338 f.close()
338
339
339 # Kill off any leftover daemon processes
340 # Kill off any leftover daemon processes
340 try:
341 try:
341 fp = file(DAEMON_PIDS)
342 fp = file(DAEMON_PIDS)
342 for line in fp:
343 for line in fp:
343 try:
344 try:
344 pid = int(line)
345 pid = int(line)
345 except ValueError:
346 except ValueError:
346 continue
347 continue
347 try:
348 try:
348 os.kill(pid, 0)
349 os.kill(pid, 0)
349 vlog('# Killing daemon process %d' % pid)
350 vlog('# Killing daemon process %d' % pid)
350 os.kill(pid, signal.SIGTERM)
351 os.kill(pid, signal.SIGTERM)
351 time.sleep(0.25)
352 time.sleep(0.25)
352 os.kill(pid, 0)
353 os.kill(pid, 0)
353 vlog('# Daemon process %d is stuck - really killing it' % pid)
354 vlog('# Daemon process %d is stuck - really killing it' % pid)
354 os.kill(pid, signal.SIGKILL)
355 os.kill(pid, signal.SIGKILL)
355 except OSError, err:
356 except OSError, err:
356 if err.errno != errno.ESRCH:
357 if err.errno != errno.ESRCH:
357 raise
358 raise
358 fp.close()
359 fp.close()
359 os.unlink(DAEMON_PIDS)
360 os.unlink(DAEMON_PIDS)
360 except IOError:
361 except IOError:
361 pass
362 pass
362
363
363 os.chdir(TESTDIR)
364 os.chdir(TESTDIR)
364 shutil.rmtree(tmpd, True)
365 shutil.rmtree(tmpd, True)
365 if skipped:
366 if skipped:
366 return None
367 return None
367 return ret == 0
368 return ret == 0
368
369
369
370
370 os.umask(022)
371 os.umask(022)
371
372
372 check_required_tools()
373 check_required_tools()
373
374
374 # Reset some environment variables to well-known values so that
375 # Reset some environment variables to well-known values so that
375 # the tests produce repeatable output.
376 # the tests produce repeatable output.
376 os.environ['LANG'] = os.environ['LC_ALL'] = 'C'
377 os.environ['LANG'] = os.environ['LC_ALL'] = 'C'
377 os.environ['TZ'] = 'GMT'
378 os.environ['TZ'] = 'GMT'
378
379
379 TESTDIR = os.environ["TESTDIR"] = os.getcwd()
380 TESTDIR = os.environ["TESTDIR"] = os.getcwd()
380 HGTMP = os.environ["HGTMP"] = tempfile.mkdtemp("", "hgtests.")
381 HGTMP = os.environ["HGTMP"] = tempfile.mkdtemp("", "hgtests.")
381 DAEMON_PIDS = os.environ["DAEMON_PIDS"] = os.path.join(HGTMP, 'daemon.pids')
382 DAEMON_PIDS = os.environ["DAEMON_PIDS"] = os.path.join(HGTMP, 'daemon.pids')
382 HGRCPATH = os.environ["HGRCPATH"] = os.path.join(HGTMP, '.hgrc')
383 HGRCPATH = os.environ["HGRCPATH"] = os.path.join(HGTMP, '.hgrc')
383
384
384 os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
385 os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
385 os.environ["HGMERGE"] = ('python "%s" -L my -L other'
386 os.environ["HGMERGE"] = ('python "%s" -L my -L other'
386 % os.path.join(TESTDIR, os.path.pardir, 'contrib',
387 % os.path.join(TESTDIR, os.path.pardir, 'contrib',
387 'simplemerge'))
388 'simplemerge'))
388 os.environ["HGUSER"] = "test"
389 os.environ["HGUSER"] = "test"
389 os.environ["HGENCODING"] = "ascii"
390 os.environ["HGENCODING"] = "ascii"
390 os.environ["HGENCODINGMODE"] = "strict"
391 os.environ["HGENCODINGMODE"] = "strict"
391
392
392 vlog("# Using TESTDIR", TESTDIR)
393 vlog("# Using TESTDIR", TESTDIR)
393 vlog("# Using HGTMP", HGTMP)
394 vlog("# Using HGTMP", HGTMP)
394
395
395 INST = os.path.join(HGTMP, "install")
396 INST = os.path.join(HGTMP, "install")
396 BINDIR = os.path.join(INST, "bin")
397 BINDIR = os.path.join(INST, "bin")
397 PYTHONDIR = os.path.join(INST, "lib", "python")
398 PYTHONDIR = os.path.join(INST, "lib", "python")
398 COVERAGE_FILE = os.path.join(TESTDIR, ".coverage")
399 COVERAGE_FILE = os.path.join(TESTDIR, ".coverage")
399
400
400 try:
401 try:
401 try:
402 try:
402 install_hg()
403 install_hg()
403
404
404 if options.timeout > 0:
405 if options.timeout > 0:
405 try:
406 try:
406 signal.signal(signal.SIGALRM, alarmed)
407 signal.signal(signal.SIGALRM, alarmed)
407 vlog('# Running tests with %d-second timeout' %
408 vlog('# Running tests with %d-second timeout' %
408 options.timeout)
409 options.timeout)
409 except AttributeError:
410 except AttributeError:
410 print 'WARNING: cannot run tests with timeouts'
411 print 'WARNING: cannot run tests with timeouts'
411 options.timeout = 0
412 options.timeout = 0
412
413
413 tested = 0
414 tested = 0
414 failed = 0
415 failed = 0
415 skipped = 0
416 skipped = 0
416
417
417 if len(args) == 0:
418 if len(args) == 0:
418 args = os.listdir(".")
419 args = os.listdir(".")
419 args.sort()
420 args.sort()
420
421
421
422
422 tests = []
423 tests = []
423 for test in args:
424 for test in args:
424 if (test.startswith("test-") and '~' not in test and
425 if (test.startswith("test-") and '~' not in test and
425 ('.' not in test or test.endswith('.py') or
426 ('.' not in test or test.endswith('.py') or
426 test.endswith('.bat'))):
427 test.endswith('.bat'))):
427 tests.append(test)
428 tests.append(test)
428
429
429 if options.restart:
430 if options.restart:
430 orig = list(tests)
431 orig = list(tests)
431 while tests:
432 while tests:
432 if os.path.exists(tests[0] + ".err"):
433 if os.path.exists(tests[0] + ".err"):
433 break
434 break
434 tests.pop(0)
435 tests.pop(0)
435 if not tests:
436 if not tests:
436 print "running all tests"
437 print "running all tests"
437 tests = orig
438 tests = orig
438
439
439 for test in tests:
440 for test in tests:
440 if options.retest and not os.path.exists(test + ".err"):
441 if options.retest and not os.path.exists(test + ".err"):
441 skipped += 1
442 skipped += 1
442 continue
443 continue
443 ret = run_one(test)
444 ret = run_one(test)
444 if ret is None:
445 if ret is None:
445 skipped += 1
446 skipped += 1
446 elif not ret:
447 elif not ret:
447 if options.interactive:
448 if options.interactive:
448 print "Accept this change? [n] ",
449 print "Accept this change? [n] ",
449 answer = sys.stdin.readline().strip()
450 answer = sys.stdin.readline().strip()
450 if answer.lower() in "y yes".split():
451 if answer.lower() in "y yes".split():
451 os.rename(test + ".err", test + ".out")
452 os.rename(test + ".err", test + ".out")
452 tested += 1
453 tested += 1
453 continue
454 continue
454 failed += 1
455 failed += 1
455 if options.first:
456 if options.first:
456 break
457 break
457 tested += 1
458 tested += 1
458
459
459 print "\n# Ran %d tests, %d skipped, %d failed." % (tested, skipped,
460 print "\n# Ran %d tests, %d skipped, %d failed." % (tested, skipped,
460 failed)
461 failed)
461 if coverage:
462 if coverage:
462 output_coverage()
463 output_coverage()
463 except KeyboardInterrupt:
464 except KeyboardInterrupt:
464 failed = True
465 failed = True
465 print "\ninterrupted!"
466 print "\ninterrupted!"
466 finally:
467 finally:
467 cleanup_exit()
468 cleanup_exit()
468
469
469 if failed:
470 if failed:
470 sys.exit(1)
471 sys.exit(1)
General Comments 0
You need to be logged in to leave comments. Login now