##// END OF EJS Templates
Tidyups for run-tests.py inc. try/finally cleanup and allow tests to be specified on command line
Stephen Darnell -
r2133:4334be19 default
parent child Browse files
Show More
@@ -1,192 +1,201 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 os, sys, shutil, re
10 import os, sys, shutil, re
11 import tempfile
11 import tempfile
12 import difflib
12 import difflib
13 import popen2
13 import popen2
14 from optparse import OptionParser
14 from optparse import OptionParser
15
15
16 required_tools = ["python", "diff", "grep", "unzip", "gunzip", "bunzip2", "sed"]
16 required_tools = ["python", "diff", "grep", "unzip", "gunzip", "bunzip2", "sed"]
17
17
18 parser = OptionParser()
18 parser = OptionParser()
19 parser.add_option("-v", "--verbose", action="store_true", dest="verbose",
19 parser.add_option("-v", "--verbose", action="store_true", dest="verbose",
20 default=False, help="output verbose messages")
20 default=False, help="output verbose messages")
21 (options, args) = parser.parse_args()
21 (options, args) = parser.parse_args()
22 verbose = options.verbose
22 verbose = options.verbose
23
23
24 def vlog(*msg):
24 def vlog(*msg):
25 if verbose:
25 if verbose:
26 for m in msg:
26 for m in msg:
27 print m,
27 print m,
28 print
28 print
29
29
30 def show_diff(expected, output):
30 def show_diff(expected, output):
31 for line in difflib.unified_diff(expected, output,
31 for line in difflib.unified_diff(expected, output,
32 "Expected output", "Test output", lineterm=''):
32 "Expected output", "Test output", lineterm=''):
33 print line
33 print line
34
34
35 def find_program(program):
35 def find_program(program):
36 """Search PATH for a executable program"""
36 """Search PATH for a executable program"""
37 for p in os.environ.get('PATH', os.defpath).split(os.pathsep):
37 for p in os.environ.get('PATH', os.defpath).split(os.pathsep):
38 name = os.path.join(p, program)
38 name = os.path.join(p, program)
39 if os.access(name, os.X_OK):
39 if os.access(name, os.X_OK):
40 return name
40 return name
41 return None
41 return None
42
42
43 # Before we go any further, check for pre-requisite tools
43 def check_required_tools():
44 # stuff from coreutils (cat, rm, etc) are not tested
44 # Before we go any further, check for pre-requisite tools
45 for p in required_tools:
45 # stuff from coreutils (cat, rm, etc) are not tested
46 if os.name == 'nt':
46 for p in required_tools:
47 p += '.exe'
47 if os.name == 'nt':
48 found = find_program(p)
48 p += '.exe'
49 if found:
49 found = find_program(p)
50 vlog("# Found prerequisite", p, "at", found)
50 if found:
51 else:
51 vlog("# Found prerequisite", p, "at", found)
52 print "WARNING: Did not find prerequisite tool: "+p
52 else:
53
53 print "WARNING: Did not find prerequisite tool: "+p
54 # Reset some environment variables to well-known values
55 os.environ['LANG'] = os.environ['LC_ALL'] = 'C'
56 os.environ['TZ'] = 'GMT'
57
58 os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
59 os.environ["HGMERGE"] = sys.executable + ' -c "import sys; sys.exit(0)"'
60 os.environ["HGUSER"] = "test"
61 os.environ["HGRCPATH"] = ""
62
63 TESTDIR = os.environ["TESTDIR"] = os.getcwd()
64 HGTMP = os.environ["HGTMP"] = tempfile.mkdtemp("", "hgtests.")
65
54
66 def cleanup_exit():
55 def cleanup_exit():
67 if verbose:
56 if verbose:
68 print "# Cleaning up HGTMP", HGTMP
57 print "# Cleaning up HGTMP", HGTMP
69 shutil.rmtree(HGTMP, True)
58 shutil.rmtree(HGTMP, True)
70
59
71 vlog("# Using TESTDIR", TESTDIR)
60 def install_hg():
72 vlog("# Using HGTMP", HGTMP)
61 vlog("# Performing temporary installation of HG")
73
62 INST = os.path.join(HGTMP, "install")
74 os.umask(022)
63 BINDIR = os.path.join(INST, "bin")
75
64 PYTHONDIR = os.path.join(INST, "lib", "python")
76 vlog("# Performing temporary installation of HG")
65 installerrs = os.path.join("tests", "install.err")
77 INST = os.path.join(HGTMP, "install")
78 BINDIR = os.path.join(INST, "bin")
79 PYTHONDIR = os.path.join(INST, "lib", "python")
80 installerrs = os.path.join("tests", "install.err")
81
66
82 os.chdir("..") # Get back to hg root
67 os.chdir("..") # Get back to hg root
83 cmd = '%s setup.py install --home="%s" --install-lib="%s" >%s 2>&1' % \
68 cmd = '%s setup.py install --home="%s" --install-lib="%s" >%s 2>&1' % \
84 (sys.executable, INST, PYTHONDIR, installerrs)
69 (sys.executable, INST, PYTHONDIR, installerrs)
85 vlog("# Running", cmd)
70 vlog("# Running", cmd)
86 if os.system(cmd) == 0:
71 if os.system(cmd) == 0:
87 if not verbose:
72 if not verbose:
88 os.remove(installerrs)
73 os.remove(installerrs)
89 else:
74 else:
90 f = open(installerrs)
75 f = open(installerrs)
91 for line in f:
76 for line in f:
92 print line,
77 print line,
93 f.close()
78 f.close()
94 cleanup_exit()
79 sys.exit(1)
95 sys.exit(1)
80 os.chdir(TESTDIR)
96 os.chdir(TESTDIR)
97
81
98 os.environ["PATH"] = "%s%s%s" % (BINDIR, os.pathsep, os.environ["PATH"])
82 os.environ["PATH"] = "%s%s%s" % (BINDIR, os.pathsep, os.environ["PATH"])
99 os.environ["PYTHONPATH"] = PYTHONDIR
83 os.environ["PYTHONPATH"] = PYTHONDIR
100
101 tests = 0
102 failed = 0
103
84
104 def run(cmd, split_lines=True):
85 def run(cmd, split_lines=True):
105 """Run command in a sub-process, capturing the output (stdout and stderr).
86 """Run command in a sub-process, capturing the output (stdout and stderr).
106 Return the exist code, and output."""
87 Return the exist code, and output."""
107 # TODO: Use subprocess.Popen if we're running on Python 2.4
88 # TODO: Use subprocess.Popen if we're running on Python 2.4
108 if os.name == 'nt':
89 if os.name == 'nt':
109 tochild, fromchild = os.popen4(cmd)
90 tochild, fromchild = os.popen4(cmd)
110 tochild.close()
91 tochild.close()
111 output = fromchild.read()
92 output = fromchild.read()
112 ret = fromchild.close()
93 ret = fromchild.close()
113 if ret == None:
94 if ret == None:
114 ret = 0
95 ret = 0
115 else:
96 else:
116 proc = popen2.Popen4(cmd)
97 proc = popen2.Popen4(cmd)
117 proc.tochild.close()
98 proc.tochild.close()
118 output = proc.fromchild.read()
99 output = proc.fromchild.read()
119 ret = proc.wait()
100 ret = proc.wait()
120 if split_lines:
101 if split_lines:
121 output = output.splitlines()
102 output = output.splitlines()
122 return ret, output
103 return ret, output
123
104
124 def run_one(test):
105 def run_one(test):
125 vlog("# Test", test)
106 vlog("# Test", test)
126 if not verbose:
107 if not verbose:
127 sys.stdout.write('.')
108 sys.stdout.write('.')
128 sys.stdout.flush()
109 sys.stdout.flush()
129
110
130 err = os.path.join(TESTDIR, test+".err")
111 err = os.path.join(TESTDIR, test+".err")
131 ref = os.path.join(TESTDIR, test+".out")
112 ref = os.path.join(TESTDIR, test+".out")
132
113
133 if os.path.exists(err):
114 if os.path.exists(err):
134 os.remove(err) # Remove any previous output files
115 os.remove(err) # Remove any previous output files
135
116
136 # Make a tmp subdirectory to work in
117 # Make a tmp subdirectory to work in
137 tmpd = os.path.join(HGTMP, test)
118 tmpd = os.path.join(HGTMP, test)
138 os.mkdir(tmpd)
119 os.mkdir(tmpd)
139 os.chdir(tmpd)
120 os.chdir(tmpd)
140
121
141 if test.endswith(".py"):
122 if test.endswith(".py"):
142 cmd = '%s "%s"' % (sys.executable, os.path.join(TESTDIR, test))
123 cmd = '%s "%s"' % (sys.executable, os.path.join(TESTDIR, test))
143 else:
124 else:
144 cmd = '"%s"' % (os.path.join(TESTDIR, test))
125 cmd = '"%s"' % (os.path.join(TESTDIR, test))
145
126
146 # To reliably get the error code from batch files on WinXP,
127 # To reliably get the error code from batch files on WinXP,
147 # the "cmd /c call" prefix is needed. Grrr
128 # the "cmd /c call" prefix is needed. Grrr
148 if os.name == 'nt' and test.endswith(".bat"):
129 if os.name == 'nt' and test.endswith(".bat"):
149 cmd = 'cmd /c call "%s"' % (os.path.join(TESTDIR, test))
130 cmd = 'cmd /c call "%s"' % (os.path.join(TESTDIR, test))
150
131
151 vlog("# Running", cmd)
132 vlog("# Running", cmd)
152 ret, out = run(cmd)
133 ret, out = run(cmd)
153 vlog("# Ret was:", ret)
134 vlog("# Ret was:", ret)
154
135
155 if ret == 0:
136 if ret == 0:
156 # If reference output file exists, check test output against it
137 # If reference output file exists, check test output against it
157 if os.path.exists(ref):
138 if os.path.exists(ref):
158 f = open(ref, "r")
139 f = open(ref, "r")
159 ref_out = f.read().splitlines()
140 ref_out = f.read().splitlines()
160 f.close()
141 f.close()
161 if out != ref_out:
142 if out != ref_out:
162 ret = 1
143 ret = 1
163 print "\nERROR: %s output changed" % (test)
144 print "\nERROR: %s output changed" % (test)
164 show_diff(ref_out, out)
145 show_diff(ref_out, out)
165 else:
146 else:
166 print "\nERROR: %s failed with error code %d" % (test, ret)
147 print "\nERROR: %s failed with error code %d" % (test, ret)
167
148
168 if ret != 0: # Save errors to a file for diagnosis
149 if ret != 0: # Save errors to a file for diagnosis
169 f = open(err, "w")
150 f = open(err, "w")
170 for line in out:
151 for line in out:
171 f.write(line)
152 f.write(line)
172 f.write("\n")
153 f.write("\n")
173 f.close()
154 f.close()
174
155
175 os.chdir(TESTDIR)
156 os.chdir(TESTDIR)
176 shutil.rmtree(tmpd, True)
157 shutil.rmtree(tmpd, True)
177 return ret == 0
158 return ret == 0
178
159
179 for test in os.listdir("."):
160
180 if test.startswith("test-"):
161 os.umask(022)
181 if '~' in test or re.search(r'\.(out|err)$', test):
162
182 continue
163 check_required_tools()
183 if not run_one(test):
164
184 failed += 1
165 # Reset some environment variables to well-known values so that
185 tests += 1
166 # the tests produce repeatable output.
167 os.environ['LANG'] = os.environ['LC_ALL'] = 'C'
168 os.environ['TZ'] = 'GMT'
169
170 os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
171 os.environ["HGMERGE"] = sys.executable + ' -c "import sys; sys.exit(0)"'
172 os.environ["HGUSER"] = "test"
173 os.environ["HGRCPATH"] = ""
174
175 TESTDIR = os.environ["TESTDIR"] = os.getcwd()
176 HGTMP = os.environ["HGTMP"] = tempfile.mkdtemp("", "hgtests.")
177 vlog("# Using TESTDIR", TESTDIR)
178 vlog("# Using HGTMP", HGTMP)
186
179
187 print "# Ran %d tests, %d failed." % (tests, failed)
180 try:
181 install_hg()
182
183 tests = 0
184 failed = 0
188
185
189 cleanup_exit()
186 if len(args) == 0:
187 args = os.listdir(".")
188 for test in args:
189 if test.startswith("test-"):
190 if '~' in test or re.search(r'\.(out|err)$', test):
191 continue
192 if not run_one(test):
193 failed += 1
194 tests += 1
195
196 print "\n# Ran %d tests, %d failed." % (tests, failed)
197 finally:
198 cleanup_exit()
190
199
191 if failed:
200 if failed:
192 sys.exit(1)
201 sys.exit(1)
General Comments 0
You need to be logged in to leave comments. Login now