10637.3.1
by Guilherme Salgado
Use the default python version instead of a hard-coded version |
1 |
#!/usr/bin/python -S
|
8687.15.10
by Karl Fogel
Add the copyright header block to top-level files. |
2 |
#
|
3 |
# Copyright 2009 Canonical Ltd. This software is licensed under the
|
|
4 |
# GNU Affero General Public License version 3 (see the file LICENSE).
|
|
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
5 |
|
6 |
"""Tests that get run automatically on a merge."""
|
|
9722.1.1
by Gary Poster
[testfix][r=salgado][ui=none] Try to fix the buildbot problem: buildbot is starting test_on_merge in a way that no-one else is. |
7 |
import _pythonpath |
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
8 |
|
10303.1.16
by Gary Poster
remove disgusting bit: we will change buildbot |
9 |
import sys, time |
10 |
import os, errno |
|
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
11 |
import tabnanny |
12 |
from StringIO import StringIO |
|
5821.2.85
by James Henstridge
Add "make check_launchpad_storm_on_merge" target that runs the tests |
13 |
import psycopg2 |
3308.1.2
by Stuart Bishop
Make test_on_merge.py do incremental output |
14 |
from subprocess import Popen, PIPE, STDOUT |
10866.2.1
by Maris Fogels
Rewrote the signal handling to move the sentinal into its own process group, where it won't be killed along with its children. Move the process group control code from the testrunner into the sentinal. |
15 |
from signal import SIGKILL, SIGTERM, SIGINT, SIGHUP |
2083
by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?) |
16 |
from select import select |
17 |
||
10866.2.1
by Maris Fogels
Rewrote the signal handling to move the sentinal into its own process group, where it won't be killed along with its children. Move the process group control code from the testrunner into the sentinal. |
18 |
|
6393.2.1
by Joey Stanford
change the rather long timeout setting to something more reasonable and cleanup the explaination |
19 |
# The TIMEOUT setting (expressed in seconds) affects how long a test will run
|
20 |
# before it is deemed to be hung, and then appropriately terminated.
|
|
21 |
# It's principal use is preventing a PQM job from hanging indefinitely and
|
|
22 |
# backing up the queue.
|
|
10866.2.2
by Maris Fogels
Lowered the test timeout a bit. |
23 |
# e.g. Usage: TIMEOUT = 60 * 10
|
24 |
# This will set the timeout to 10 minutes.
|
|
25 |
TIMEOUT = 60 * 10 |
|
10866.2.1
by Maris Fogels
Rewrote the signal handling to move the sentinal into its own process group, where it won't be killed along with its children. Move the process group control code from the testrunner into the sentinal. |
26 |
|
10866.2.7
by Maris Fogels
Split test_on_merge.py into functions, marked the tabnanny code as broken and needing fixing, and added a test process fork to address the case where the script was started directly from the command line. |
27 |
HERE = os.path.dirname(os.path.realpath(__file__)) |
28 |
||
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
29 |
|
30 |
def main(): |
|
8234.1.4
by Gary Poster
test works, nominally; and bin/py is a bit more functional. problems with import warnings are more serious because they cause tests to fail. |
31 |
"""Call bin/test with whatever arguments this script was run with.
|
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
32 |
|
10866.2.14
by Maris Fogels
Remove the tabnanny code as pocketlint and text editors already catch this stuff. |
33 |
Prior to running the tests this script sets up the test database.
|
10866.2.7
by Maris Fogels
Split test_on_merge.py into functions, marked the tabnanny code as broken and needing fixing, and added a test process fork to address the case where the script was started directly from the command line. |
34 |
|
35 |
Returns 1 on error, otherwise it returns the testrunner's exit code.
|
|
36 |
"""
|
|
37 |
if setup_test_database() != 0: |
|
38 |
return 1 |
|
39 |
||
40 |
return run_test_process() |
|
41 |
||
42 |
||
43 |
def setup_test_database(): |
|
44 |
"""Set up a test instance of our postgresql database.
|
|
45 |
||
46 |
Returns 0 for success, 1 for errors.
|
|
47 |
"""
|
|
1064.1.3
by James Henstridge
merge from marius |
48 |
# Sanity check PostgreSQL version. No point in trying to create a test
|
49 |
# database when PostgreSQL is too old.
|
|
5821.2.85
by James Henstridge
Add "make check_launchpad_storm_on_merge" target that runs the tests |
50 |
con = psycopg2.connect('dbname=template1') |
1064.1.3
by James Henstridge
merge from marius |
51 |
cur = con.cursor() |
52 |
cur.execute('show server_version') |
|
53 |
server_version = cur.fetchone()[0] |
|
54 |
try: |
|
55 |
numeric_server_version = tuple(map(int, server_version.split('.'))) |
|
56 |
except ValueError: |
|
57 |
# Skip this check if the version number is more complicated than
|
|
58 |
# we expected.
|
|
59 |
pass
|
|
60 |
else: |
|
3257.1.1
by Stuart Bishop
PostgreSQL 8.0+ required |
61 |
if numeric_server_version < (8, 0): |
62 |
print 'Your PostgreSQL version is too old. You need 8.x.x' |
|
1064.1.3
by James Henstridge
merge from marius |
63 |
print 'You have %s' % server_version |
64 |
return 1 |
|
65 |
||
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
66 |
# Drop the template database if it exists - the Makefile does this
|
67 |
# too, but we can explicity check for errors here
|
|
5821.2.85
by James Henstridge
Add "make check_launchpad_storm_on_merge" target that runs the tests |
68 |
con = psycopg2.connect('dbname=template1') |
2083
by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?) |
69 |
con.set_isolation_level(0) |
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
70 |
cur = con.cursor() |
1064.1.3
by James Henstridge
merge from marius |
71 |
try: |
2083
by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?) |
72 |
cur.execute('drop database launchpad_ftest_template') |
5821.2.85
by James Henstridge
Add "make check_launchpad_storm_on_merge" target that runs the tests |
73 |
except psycopg2.ProgrammingError, x: |
1520
by Canonical.com Patch Queue Manager
Review and fix database security update code |
74 |
if 'does not exist' not in str(x): |
75 |
raise
|
|
2083
by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?) |
76 |
cur.execute(""" |
77 |
select count(*) from pg_stat_activity
|
|
78 |
where datname in ('launchpad_dev',
|
|
79 |
'launchpad_ftest_template', 'launchpad_ftest')
|
|
80 |
""") |
|
81 |
existing_connections = cur.fetchone()[0] |
|
82 |
if existing_connections > 0: |
|
83 |
print 'Cannot rebuild database. There are %d open connections.' % ( |
|
84 |
existing_connections, |
|
85 |
)
|
|
86 |
return 1 |
|
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
87 |
cur.close() |
88 |
con.close() |
|
89 |
||
90 |
# Build the template database. Tests duplicate this.
|
|
10866.2.7
by Maris Fogels
Split test_on_merge.py into functions, marked the tabnanny code as broken and needing fixing, and added a test process fork to address the case where the script was started directly from the command line. |
91 |
schema_dir = os.path.join(HERE, 'database', 'schema') |
10303.1.15
by Gary Poster
make test_on_merge.py work, so buildbot can pass |
92 |
if os.system('cd %s; make test > /dev/null' % (schema_dir)) != 0: |
1764
by Canonical.com Patch Queue Manager
Now make check fails if anything goes wrong when loading the sampledata. r=stub |
93 |
print 'Failed to create database or load sampledata.' |
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
94 |
return 1 |
95 |
||
96 |
# Sanity check the database. No point running tests if the
|
|
97 |
# bedrock is crumbling.
|
|
5821.2.85
by James Henstridge
Add "make check_launchpad_storm_on_merge" target that runs the tests |
98 |
con = psycopg2.connect('dbname=launchpad_ftest_template') |
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
99 |
cur = con.cursor() |
100 |
cur.execute('show search_path') |
|
101 |
search_path = cur.fetchone()[0] |
|
102 |
if search_path != '$user,public,ts2': |
|
103 |
print 'Search path incorrect.' |
|
104 |
print 'Add the following line to /etc/postgresql/postgresql.conf:' |
|
105 |
print " search_path = '$user,public,ts2'" |
|
1064.1.3
by James Henstridge
merge from marius |
106 |
print "and tell postgresql to reload its configuration file." |
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
107 |
return 1 |
108 |
cur.execute(""" |
|
109 |
select pg_encoding_to_char(encoding) as encoding from pg_database
|
|
110 |
where datname='launchpad_ftest_template'
|
|
111 |
""") |
|
112 |
enc = cur.fetchone()[0] |
|
3242.1.5
by Stuart Bishop
Make test_on_merge.py work with PostgreSQL 8.1 |
113 |
if enc not in ('UNICODE', 'UTF8'): |
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
114 |
print 'Database encoding incorrectly set' |
115 |
return 1 |
|
1257
by Canonical.com Patch Queue Manager
Improve database locale checks, add locale sanity check to test_on_merge.py and improve test_on_merge output |
116 |
cur.execute(r""" |
117 |
SELECT setting FROM pg_settings
|
|
118 |
WHERE context='internal' AND name='lc_ctype'
|
|
119 |
""") |
|
120 |
loc = cur.fetchone()[0] |
|
2083
by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?) |
121 |
#if not (loc.startswith('en_') or loc in ('C', 'en')):
|
122 |
if loc != 'C': |
|
1257
by Canonical.com Patch Queue Manager
Improve database locale checks, add locale sanity check to test_on_merge.py and improve test_on_merge output |
123 |
print 'Database locale incorrectly set. Need to rerun initdb.' |
124 |
return 1 |
|
125 |
||
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
126 |
# Explicity close our connections - things will fail if we leave open
|
127 |
# connections.
|
|
128 |
cur.close() |
|
129 |
del cur |
|
130 |
con.close() |
|
131 |
del con |
|
132 |
||
10866.2.7
by Maris Fogels
Split test_on_merge.py into functions, marked the tabnanny code as broken and needing fixing, and added a test process fork to address the case where the script was started directly from the command line. |
133 |
return 0 |
134 |
||
135 |
||
136 |
def run_test_process(): |
|
137 |
"""Start the testrunner process and return its exit code."""
|
|
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
138 |
print 'Running tests.' |
10866.2.7
by Maris Fogels
Split test_on_merge.py into functions, marked the tabnanny code as broken and needing fixing, and added a test process fork to address the case where the script was started directly from the command line. |
139 |
os.chdir(HERE) |
10866.2.1
by Maris Fogels
Rewrote the signal handling to move the sentinal into its own process group, where it won't be killed along with its children. Move the process group control code from the testrunner into the sentinal. |
140 |
|
141 |
# We run the test suite under a virtual frame buffer server so that the
|
|
142 |
# JavaScript integration test suite can run.
|
|
10096.2.2
by Bjorn Tillenius
Run xvfb-run inside test_on_merge.py. |
143 |
cmd = [ |
10866.2.15
by Maris Fogels
Re-added the shell option to our subprocess call. The script fails with strange errors if we do not include this option. |
144 |
'/usr/bin/xvfb-run', |
11243.1.1
by Maris Fogels
Make Xvfb log its startup errors, and clarify the startup arguments a bit. |
145 |
"--error-file=/var/tmp/xvfb-errors.log", |
146 |
"--server-args='-screen 0 1024x768x24'", |
|
10866.2.7
by Maris Fogels
Split test_on_merge.py into functions, marked the tabnanny code as broken and needing fixing, and added a test process fork to address the case where the script was started directly from the command line. |
147 |
os.path.join(HERE, 'bin', 'test')] + sys.argv[1:] |
10096.2.3
by Bjorn Tillenius
Use xvfb-run in test_on_merge.py |
148 |
command_line = ' '.join(cmd) |
10866.2.1
by Maris Fogels
Rewrote the signal handling to move the sentinal into its own process group, where it won't be killed along with its children. Move the process group control code from the testrunner into the sentinal. |
149 |
print "Running command:", command_line |
4107.1.9
by Stuart Bishop
Increase test_on_merge timeout to one hour |
150 |
|
10866.2.12
by Maris Fogels
Simplified much of the process killing and shenanigans code. |
151 |
# Run the test suite. Make the suite the leader of a new process group
|
152 |
# so that we can signal the group without signaling ourselves.
|
|
10866.2.1
by Maris Fogels
Rewrote the signal handling to move the sentinal into its own process group, where it won't be killed along with its children. Move the process group control code from the testrunner into the sentinal. |
153 |
xvfb_proc = Popen( |
10866.2.12
by Maris Fogels
Simplified much of the process killing and shenanigans code. |
154 |
command_line, |
155 |
stdout=PIPE, |
|
156 |
stderr=STDOUT, |
|
10866.2.15
by Maris Fogels
Re-added the shell option to our subprocess call. The script fails with strange errors if we do not include this option. |
157 |
preexec_fn=os.setpgrp, |
158 |
shell=True) |
|
10866.2.1
by Maris Fogels
Rewrote the signal handling to move the sentinal into its own process group, where it won't be killed along with its children. Move the process group control code from the testrunner into the sentinal. |
159 |
|
10866.2.4
by Maris Fogels
Tidied the code for review. |
160 |
# This code is very similar to what takes place in Popen._communicate(),
|
10866.2.1
by Maris Fogels
Rewrote the signal handling to move the sentinal into its own process group, where it won't be killed along with its children. Move the process group control code from the testrunner into the sentinal. |
161 |
# but this code times out if there is no activity on STDOUT for too long.
|
10866.2.12
by Maris Fogels
Simplified much of the process killing and shenanigans code. |
162 |
# This keeps us from blocking when reading from a hung testrunner, allows
|
163 |
# us to time out if the child process hangs, and avoids issues when using
|
|
164 |
# Popen.communicate() with large data sets.
|
|
10866.2.1
by Maris Fogels
Rewrote the signal handling to move the sentinal into its own process group, where it won't be killed along with its children. Move the process group control code from the testrunner into the sentinal. |
165 |
open_readers = set([xvfb_proc.stdout]) |
3308.1.4
by Stuart Bishop
Fix test_on_merge.py incremental output |
166 |
while open_readers: |
2083
by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?) |
167 |
rlist, wlist, xlist = select(open_readers, [], [], TIMEOUT) |
168 |
||
4092.2.18
by Barry Warsaw
Respond to spiv's review: |
169 |
if len(rlist) == 0: |
10866.2.1
by Maris Fogels
Rewrote the signal handling to move the sentinal into its own process group, where it won't be killed along with its children. Move the process group control code from the testrunner into the sentinal. |
170 |
# The select() statement timed out!
|
171 |
||
172 |
if xvfb_proc.poll() is not None: |
|
173 |
# The process we were watching died.
|
|
2083
by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?) |
174 |
break
|
10866.2.1
by Maris Fogels
Rewrote the signal handling to move the sentinal into its own process group, where it won't be killed along with its children. Move the process group control code from the testrunner into the sentinal. |
175 |
|
10866.2.5
by Maris Fogels
Nicer function name |
176 |
cleanup_hung_testrunner(xvfb_proc) |
4092.2.12
by Barry Warsaw
Thanks to jamesh, do a better job of draining the subprocess's stdout and |
177 |
break
|
2083
by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?) |
178 |
|
10866.2.1
by Maris Fogels
Rewrote the signal handling to move the sentinal into its own process group, where it won't be killed along with its children. Move the process group control code from the testrunner into the sentinal. |
179 |
if xvfb_proc.stdout in rlist: |
180 |
# Read a chunk of output from STDOUT.
|
|
181 |
chunk = os.read(xvfb_proc.stdout.fileno(), 1024) |
|
3367.1.2
by Stuart Bishop
Don't insert random spaces in test_on_merge.py output |
182 |
sys.stdout.write(chunk) |
3308.1.2
by Stuart Bishop
Make test_on_merge.py do incremental output |
183 |
if chunk == "": |
10866.2.1
by Maris Fogels
Rewrote the signal handling to move the sentinal into its own process group, where it won't be killed along with its children. Move the process group control code from the testrunner into the sentinal. |
184 |
# Gracefully exit the loop if STDOUT is empty.
|
185 |
open_readers.remove(xvfb_proc.stdout) |
|
186 |
||
10866.2.4
by Maris Fogels
Tidied the code for review. |
187 |
rv = xvfb_proc.wait() |
10866.2.1
by Maris Fogels
Rewrote the signal handling to move the sentinal into its own process group, where it won't be killed along with its children. Move the process group control code from the testrunner into the sentinal. |
188 |
|
3308.1.2
by Stuart Bishop
Make test_on_merge.py do incremental output |
189 |
if rv == 0: |
10866.2.1
by Maris Fogels
Rewrote the signal handling to move the sentinal into its own process group, where it won't be killed along with its children. Move the process group control code from the testrunner into the sentinal. |
190 |
print
|
191 |
print 'Successfully ran all tests.' |
|
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
192 |
else: |
10866.2.1
by Maris Fogels
Rewrote the signal handling to move the sentinal into its own process group, where it won't be killed along with its children. Move the process group control code from the testrunner into the sentinal. |
193 |
print
|
194 |
print 'Tests failed (exit code %d)' % rv |
|
3308.1.2
by Stuart Bishop
Make test_on_merge.py do incremental output |
195 |
|
196 |
return rv |
|
197 |
||
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
198 |
|
10866.2.5
by Maris Fogels
Nicer function name |
199 |
def cleanup_hung_testrunner(process): |
10866.2.4
by Maris Fogels
Tidied the code for review. |
200 |
"""Kill and clean up the testrunner process and its children."""
|
201 |
print
|
|
202 |
print
|
|
203 |
print ("WARNING: A test appears to be hung. There has been no " |
|
204 |
"output for %d seconds." % TIMEOUT) |
|
205 |
print "Forcibly shutting down the test suite" |
|
206 |
||
10866.2.12
by Maris Fogels
Simplified much of the process killing and shenanigans code. |
207 |
# This guarantees the process will die. In rare cases
|
10866.2.4
by Maris Fogels
Tidied the code for review. |
208 |
# a child process may survive this if they are in a different
|
209 |
# process group and they ignore the signals we send their parent.
|
|
10866.2.12
by Maris Fogels
Simplified much of the process killing and shenanigans code. |
210 |
nice_killpg(process.pid) |
211 |
||
212 |
# The process should absolutely be dead now.
|
|
213 |
assert process.poll() is not None |
|
10866.2.4
by Maris Fogels
Tidied the code for review. |
214 |
|
215 |
# Drain the subprocess's stdout and stderr.
|
|
216 |
print "The dying processes left behind the following output:" |
|
217 |
print "--------------- BEGIN OUTPUT ---------------" |
|
218 |
sys.stdout.write(process.stdout.read()) |
|
219 |
print
|
|
220 |
print "---------------- END OUTPUT ----------------" |
|
221 |
||
222 |
||
10866.2.12
by Maris Fogels
Simplified much of the process killing and shenanigans code. |
223 |
def nice_killpg(pgid): |
10866.2.1
by Maris Fogels
Rewrote the signal handling to move the sentinal into its own process group, where it won't be killed along with its children. Move the process group control code from the testrunner into the sentinal. |
224 |
"""Kill a Unix process group using increasingly harmful signals."""
|
2083
by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?) |
225 |
try: |
10866.2.1
by Maris Fogels
Rewrote the signal handling to move the sentinal into its own process group, where it won't be killed along with its children. Move the process group control code from the testrunner into the sentinal. |
226 |
print "Process group %d will be killed" % pgid |
227 |
||
228 |
# Attempt a series of increasingly brutal methods of killing the
|
|
229 |
# process.
|
|
230 |
for signum in [SIGTERM, SIGINT, SIGHUP, SIGKILL]: |
|
231 |
print "Sending signal %s to process group %d" % (signum, pgid) |
|
232 |
os.killpg(pgid, signum) |
|
233 |
||
234 |
# Give the processes some time to shut down.
|
|
235 |
time.sleep(3) |
|
236 |
||
237 |
except OSError, exc: |
|
238 |
if exc.errno == errno.ESRCH: |
|
239 |
# We tried to call os.killpg() and found the group to be empty.
|
|
240 |
pass
|
|
2083
by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?) |
241 |
else: |
242 |
raise
|
|
10866.2.1
by Maris Fogels
Rewrote the signal handling to move the sentinal into its own process group, where it won't be killed along with its children. Move the process group control code from the testrunner into the sentinal. |
243 |
print "Process group %d is now empty." % pgid |
244 |
||
2083
by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?) |
245 |
|
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
246 |
if __name__ == '__main__': |
247 |
sys.exit(main()) |