1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
1 |
#!/usr/bin/env python2.3
|
2 |
# Copyright 2004 Canonical Ltd. All rights reserved.
|
|
3 |
||
4 |
"""Tests that get run automatically on a merge."""
|
|
5 |
||
2083
by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?) |
6 |
import sys, re, time |
7 |
import os, os.path, errno |
|
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
8 |
import tabnanny |
9 |
from StringIO import StringIO |
|
10 |
import psycopg |
|
2083
by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?) |
11 |
from subprocess import Popen, PIPE |
12 |
from signal import SIGKILL, SIGTERM |
|
13 |
from select import select |
|
14 |
||
15 |
# Die and kill the kids if no output for 10 minutes. Tune this if if your
|
|
16 |
# slow arsed machine needs it. The main use for this is to keep the pqm
|
|
17 |
# queue flowing without having to give it a lifeless enema.
|
|
18 |
TIMEOUT = 10 * 60 |
|
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
19 |
|
20 |
def main(): |
|
21 |
"""Call test.py with whatever arguments this script was run with.
|
|
22 |
||
23 |
If the tests ran ok (last line of stderr is 'OK<return>') then suppress
|
|
24 |
output and exit(0).
|
|
25 |
||
26 |
Otherwise, print output and exit(1).
|
|
27 |
"""
|
|
28 |
here = os.path.dirname(os.path.realpath(__file__)) |
|
29 |
||
30 |
# Tabnanny
|
|
31 |
org_stdout = sys.stdout |
|
32 |
sys.stdout = StringIO() |
|
33 |
tabnanny.check(os.path.join(here, 'lib', 'canonical')) |
|
34 |
tabnanny_results = sys.stdout.getvalue() |
|
35 |
sys.stdout = org_stdout |
|
36 |
if len(tabnanny_results) > 0: |
|
37 |
print '---- tabnanny bitching ----' |
|
38 |
print tabnanny_results |
|
39 |
print '---- end tabnanny bitching ----' |
|
40 |
return 1 |
|
41 |
||
42 |
# Ensure ++resource++ URL's are all absolute - this ensures they
|
|
43 |
# are cache friendly
|
|
44 |
results = os.popen( |
|
45 |
"find lib/canonical -type f | xargs grep '[^/]++resource++'"
|
|
46 |
).readlines() |
|
47 |
if results: |
|
48 |
print '---- non-absolute ++resource++ URLs found ----' |
|
49 |
print ''.join(results) |
|
50 |
print '---- end non-absolute ++resource++ URLs found ----' |
|
51 |
return 1 |
|
52 |
||
1064.1.3
by James Henstridge
merge from marius |
53 |
# Sanity check PostgreSQL version. No point in trying to create a test
|
54 |
# database when PostgreSQL is too old.
|
|
55 |
con = psycopg.connect('dbname=template1') |
|
56 |
cur = con.cursor() |
|
57 |
cur.execute('show server_version') |
|
58 |
server_version = cur.fetchone()[0] |
|
59 |
try: |
|
60 |
numeric_server_version = tuple(map(int, server_version.split('.'))) |
|
61 |
except ValueError: |
|
62 |
# Skip this check if the version number is more complicated than
|
|
63 |
# we expected.
|
|
64 |
pass
|
|
65 |
else: |
|
66 |
if numeric_server_version < (7, 4): |
|
67 |
print 'Your PostgreSQL version is too old. You need 7.4.x' |
|
68 |
print 'You have %s' % server_version |
|
69 |
return 1 |
|
70 |
||
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
71 |
# Drop the template database if it exists - the Makefile does this
|
72 |
# too, but we can explicity check for errors here
|
|
73 |
con = psycopg.connect('dbname=template1') |
|
2083
by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?) |
74 |
con.set_isolation_level(0) |
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
75 |
cur = con.cursor() |
1064.1.3
by James Henstridge
merge from marius |
76 |
try: |
2083
by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?) |
77 |
cur.execute('drop database launchpad_ftest_template') |
1520
by Canonical.com Patch Queue Manager
Review and fix database security update code |
78 |
except psycopg.ProgrammingError, x: |
79 |
if 'does not exist' not in str(x): |
|
80 |
raise
|
|
2083
by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?) |
81 |
cur.execute(""" |
82 |
select count(*) from pg_stat_activity
|
|
83 |
where datname in ('launchpad_dev',
|
|
84 |
'launchpad_ftest_template', 'launchpad_ftest')
|
|
85 |
""") |
|
86 |
existing_connections = cur.fetchone()[0] |
|
87 |
if existing_connections > 0: |
|
88 |
print 'Cannot rebuild database. There are %d open connections.' % ( |
|
89 |
existing_connections, |
|
90 |
)
|
|
91 |
return 1 |
|
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
92 |
cur.close() |
93 |
con.close() |
|
94 |
||
95 |
||
96 |
# Build the template database. Tests duplicate this.
|
|
97 |
here = os.path.dirname(os.path.realpath(__file__)) |
|
98 |
schema_dir = os.path.join(here, 'database', 'schema') |
|
1297
by Canonical.com Patch Queue Manager
Merge in database security branch |
99 |
if os.system('cd %s; make test PYTHON=%s > /dev/null' % ( |
1155
by Canonical.com Patch Queue Manager
More robust authentication |
100 |
schema_dir, sys.executable)) != 0: |
1764
by Canonical.com Patch Queue Manager
Now make check fails if anything goes wrong when loading the sampledata. r=stub |
101 |
print 'Failed to create database or load sampledata.' |
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
102 |
return 1 |
103 |
||
104 |
# Sanity check the database. No point running tests if the
|
|
105 |
# bedrock is crumbling.
|
|
106 |
con = psycopg.connect('dbname=launchpad_ftest_template') |
|
107 |
cur = con.cursor() |
|
108 |
cur.execute('show search_path') |
|
109 |
search_path = cur.fetchone()[0] |
|
110 |
if search_path != '$user,public,ts2': |
|
111 |
print 'Search path incorrect.' |
|
112 |
print 'Add the following line to /etc/postgresql/postgresql.conf:' |
|
113 |
print " search_path = '$user,public,ts2'" |
|
1064.1.3
by James Henstridge
merge from marius |
114 |
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 |
115 |
return 1 |
116 |
cur.execute(""" |
|
117 |
select pg_encoding_to_char(encoding) as encoding from pg_database
|
|
118 |
where datname='launchpad_ftest_template'
|
|
119 |
""") |
|
120 |
enc = cur.fetchone()[0] |
|
121 |
if enc != 'UNICODE': |
|
122 |
print 'Database encoding incorrectly set' |
|
123 |
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 |
124 |
cur.execute(r""" |
125 |
SELECT setting FROM pg_settings
|
|
126 |
WHERE context='internal' AND name='lc_ctype'
|
|
127 |
""") |
|
128 |
loc = cur.fetchone()[0] |
|
2083
by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?) |
129 |
#if not (loc.startswith('en_') or loc in ('C', 'en')):
|
130 |
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 |
131 |
print 'Database locale incorrectly set. Need to rerun initdb.' |
132 |
return 1 |
|
133 |
||
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
134 |
# Explicity close our connections - things will fail if we leave open
|
135 |
# connections.
|
|
136 |
cur.close() |
|
137 |
del cur |
|
138 |
con.close() |
|
139 |
del con |
|
140 |
||
141 |
||
142 |
print 'Running tests.' |
|
2083
by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?) |
143 |
os.chdir(here) |
144 |
cmd = [sys.executable, 'test.py'] + sys.argv[1:] |
|
145 |
print ' '.join(cmd) |
|
146 |
# This would be simpler if we set stderr=STDOUT to combine the streams
|
|
147 |
proc = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE) |
|
148 |
proc.stdin.close() |
|
149 |
||
150 |
out = [] # stdout from tests |
|
151 |
err = [] # stderr from tests |
|
152 |
open_readers = set([proc.stderr, proc.stdout]) |
|
153 |
while open_readers: |
|
154 |
rlist, wlist, xlist = select(open_readers, [], [], TIMEOUT) |
|
155 |
||
156 |
if len(rlist) == 0: |
|
157 |
if proc.poll() is None: |
|
158 |
break
|
|
159 |
print 'Tests hung - no output for %d seconds. Killing.' % TIMEOUT |
|
160 |
killem(proc.pid, SIGTERM) |
|
161 |
time.sleep(3) |
|
162 |
if proc.poll() is None: |
|
163 |
print 'Not dead yet! - slaughtering mercilessly' |
|
164 |
killem(proc.pid, SIGKILL) |
|
165 |
break
|
|
166 |
||
167 |
if proc.stdout in rlist: |
|
168 |
out.append(os.read(proc.stdout.fileno(), 1024)) |
|
169 |
if out[-1] == "": |
|
170 |
open_readers.remove(proc.stdout) |
|
171 |
if proc.stderr in rlist: |
|
172 |
err.append(os.read(proc.stderr.fileno(), 1024)) |
|
173 |
if err[-1] == "": |
|
174 |
open_readers.remove(proc.stderr) |
|
175 |
||
176 |
test_ok = (proc.wait() == 0) |
|
177 |
||
178 |
out = ''.join(out) |
|
179 |
err = ''.join(err) |
|
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
180 |
|
181 |
if test_ok: |
|
2083
by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?) |
182 |
for line in err.split('\n'): |
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 |
183 |
if re.match('^Ran\s\d+\stest(s)?\sin\s[\d\.]+s$', line): |
184 |
print line |
|
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
185 |
return 0 |
186 |
else: |
|
187 |
print '---- test stdout ----' |
|
2083
by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?) |
188 |
print out |
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
189 |
print '---- end test stdout ----' |
190 |
||
191 |
print '---- test stderr ----' |
|
2083
by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?) |
192 |
print err |
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
193 |
print '---- end test stderr ----' |
194 |
return 1 |
|
195 |
||
2083
by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?) |
196 |
def killem(pid, signal): |
197 |
"""Kill the process group leader identified by pid and other group members
|
|
198 |
||
199 |
Note that test.py sets its process to a process group leader.
|
|
200 |
"""
|
|
201 |
try: |
|
202 |
os.killpg(os.getpgid(pid), signal) |
|
203 |
except OSError, x: |
|
204 |
if x.errno == errno.ESRCH: |
|
205 |
pass
|
|
206 |
else: |
|
207 |
raise
|
|
208 |
||
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
209 |
if __name__ == '__main__': |
210 |
sys.exit(main()) |