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