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