~launchpad-pqm/launchpad/devel

3944.1.1 by Francis J. Lacoste
Use system version python2.4 for scripts.
1
#!/usr/bin/python2.4
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."""
7
6393.2.2 by Joey Stanford
working updates since I had to change the line for pyflakes
8
import sys, time
9
import os, errno
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
10
import tabnanny
11
from StringIO import StringIO
5821.2.85 by James Henstridge
Add "make check_launchpad_storm_on_merge" target that runs the tests
12
import psycopg2
3308.1.2 by Stuart Bishop
Make test_on_merge.py do incremental output
13
from subprocess import Popen, PIPE, STDOUT
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
14
from signal import SIGKILL, SIGTERM
15
from select import select
16
6393.2.1 by Joey Stanford
change the rather long timeout setting to something more reasonable and cleanup the explaination
17
# The TIMEOUT setting (expressed in seconds) affects how long a test will run
18
# before it is deemed to be hung, and then appropriately terminated.
19
# It's principal use is preventing a PQM job from hanging indefinitely and
20
# backing up the queue.
21
# e.g. Usage: TIMEOUT = 60 * 15
22
# This will set the timeout to 15 minutes.
23
TIMEOUT = 60 * 15
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
24
25
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.
26
    """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
27
28
    If the tests ran ok (last line of stderr is 'OK<return>') then suppress
29
    output and exit(0).
30
31
    Otherwise, print output and exit(1).
32
    """
33
    here = os.path.dirname(os.path.realpath(__file__))
34
35
    # Tabnanny
6393.2.2 by Joey Stanford
working updates since I had to change the line for pyflakes
36
    # NB. If tabnanny raises an exception, run
2976.10.114 by Stuart Bishop
Test tweaks
37
    # python /usr/lib/python2.4/tabnanny.py -vv lib/canonical
38
    # for more detailed output.
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
39
    org_stdout = sys.stdout
40
    sys.stdout = StringIO()
41
    tabnanny.check(os.path.join(here, 'lib', 'canonical'))
42
    tabnanny_results = sys.stdout.getvalue()
43
    sys.stdout = org_stdout
44
    if len(tabnanny_results) > 0:
45
        print '---- tabnanny bitching ----'
46
        print tabnanny_results
47
        print '---- end tabnanny bitching ----'
48
        return 1
49
1064.1.3 by James Henstridge
merge from marius
50
    # Sanity check PostgreSQL version. No point in trying to create a test
51
    # database when PostgreSQL is too old.
5821.2.85 by James Henstridge
Add "make check_launchpad_storm_on_merge" target that runs the tests
52
    con = psycopg2.connect('dbname=template1')
1064.1.3 by James Henstridge
merge from marius
53
    cur = con.cursor()
54
    cur.execute('show server_version')
55
    server_version = cur.fetchone()[0]
56
    try:
57
        numeric_server_version = tuple(map(int, server_version.split('.')))
58
    except ValueError:
59
        # Skip this check if the version number is more complicated than
60
        # we expected.
61
        pass
62
    else:
3257.1.1 by Stuart Bishop
PostgreSQL 8.0+ required
63
        if numeric_server_version < (8, 0):
64
            print 'Your PostgreSQL version is too old.  You need 8.x.x'
1064.1.3 by James Henstridge
merge from marius
65
            print 'You have %s' % server_version
66
            return 1
67
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
68
    # Drop the template database if it exists - the Makefile does this
69
    # 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
70
    con = psycopg2.connect('dbname=template1')
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
71
    con.set_isolation_level(0)
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
72
    cur = con.cursor()
1064.1.3 by James Henstridge
merge from marius
73
    try:
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
74
        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
75
    except psycopg2.ProgrammingError, x:
1520 by Canonical.com Patch Queue Manager
Review and fix database security update code
76
        if 'does not exist' not in str(x):
77
            raise
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
78
    cur.execute("""
79
        select count(*) from pg_stat_activity
80
        where datname in ('launchpad_dev',
81
            'launchpad_ftest_template', 'launchpad_ftest')
82
        """)
83
    existing_connections = cur.fetchone()[0]
84
    if existing_connections > 0:
85
        print 'Cannot rebuild database. There are %d open connections.' % (
86
                existing_connections,
87
                )
88
        return 1
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
89
    cur.close()
90
    con.close()
91
92
    # Build the template database. Tests duplicate this.
93
    here = os.path.dirname(os.path.realpath(__file__))
94
    schema_dir = os.path.join(here, 'database', 'schema')
1297 by Canonical.com Patch Queue Manager
Merge in database security branch
95
    if os.system('cd %s; make test PYTHON=%s > /dev/null' % (
1155 by Canonical.com Patch Queue Manager
More robust authentication
96
        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
97
        print 'Failed to create database or load sampledata.'
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
98
        return 1
99
100
    # Sanity check the database. No point running tests if the
101
    # bedrock is crumbling.
5821.2.85 by James Henstridge
Add "make check_launchpad_storm_on_merge" target that runs the tests
102
    con = psycopg2.connect('dbname=launchpad_ftest_template')
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
103
    cur = con.cursor()
104
    cur.execute('show search_path')
105
    search_path = cur.fetchone()[0]
106
    if search_path != '$user,public,ts2':
107
        print 'Search path incorrect.'
108
        print 'Add the following line to /etc/postgresql/postgresql.conf:'
109
        print "    search_path = '$user,public,ts2'"
1064.1.3 by James Henstridge
merge from marius
110
        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
111
        return 1
112
    cur.execute("""
113
        select pg_encoding_to_char(encoding) as encoding from pg_database
114
        where datname='launchpad_ftest_template'
115
        """)
116
    enc = cur.fetchone()[0]
3242.1.5 by Stuart Bishop
Make test_on_merge.py work with PostgreSQL 8.1
117
    if enc not in ('UNICODE', 'UTF8'):
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
118
        print 'Database encoding incorrectly set'
119
        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
120
    cur.execute(r"""
121
        SELECT setting FROM pg_settings
122
        WHERE context='internal' AND name='lc_ctype'
123
        """)
124
    loc = cur.fetchone()[0]
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
125
    #if not (loc.startswith('en_') or loc in ('C', 'en')):
126
    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
127
        print 'Database locale incorrectly set. Need to rerun initdb.'
128
        return 1
129
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
130
    # Explicity close our connections - things will fail if we leave open
131
    # connections.
132
    cur.close()
133
    del cur
134
    con.close()
135
    del con
136
137
    print 'Running tests.'
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
138
    os.chdir(here)
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.
139
    cmd = [os.path.join(here, 'bin', 'test')] + sys.argv[1:]
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
140
    print ' '.join(cmd)
4107.1.9 by Stuart Bishop
Increase test_on_merge timeout to one hour
141
142
    # Run the test suite and return the error code
143
    #return call(cmd)
144
3308.1.2 by Stuart Bishop
Make test_on_merge.py do incremental output
145
    proc = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
146
    proc.stdin.close()
147
3258.1.1 by Andrew Bennetts
Fix backwards timeout detection logic in test_on_merge.py
148
    # Do proc.communicate(), but timeout if there's no activity on stdout or
149
    # stderr for too long.
3308.1.2 by Stuart Bishop
Make test_on_merge.py do incremental output
150
    open_readers = set([proc.stdout])
3308.1.4 by Stuart Bishop
Fix test_on_merge.py incremental output
151
    while open_readers:
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
152
        rlist, wlist, xlist = select(open_readers, [], [], TIMEOUT)
153
4092.2.18 by Barry Warsaw
Respond to spiv's review:
154
        if len(rlist) == 0:
3258.1.1 by Andrew Bennetts
Fix backwards timeout detection logic in test_on_merge.py
155
            if proc.poll() is not None:
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
156
                break
6393.2.2 by Joey Stanford
working updates since I had to change the line for pyflakes
157
            print ("\nA test appears to be hung. There has been no output for"
158
                " %d seconds. Sending SIGTERM." % TIMEOUT)
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
159
            killem(proc.pid, SIGTERM)
160
            time.sleep(3)
3258.1.1 by Andrew Bennetts
Fix backwards timeout detection logic in test_on_merge.py
161
            if proc.poll() is not None:
6393.2.2 by Joey Stanford
working updates since I had to change the line for pyflakes
162
                print ("\nSIGTERM did not work. Sending SIGKILL.")
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
163
                killem(proc.pid, SIGKILL)
4092.2.12 by Barry Warsaw
Thanks to jamesh, do a better job of draining the subprocess's stdout and
164
            # Drain the subprocess's stdout and stderr.
165
            sys.stdout.write(proc.stdout.read())
166
            break
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
167
168
        if proc.stdout in rlist:
3308.1.2 by Stuart Bishop
Make test_on_merge.py do incremental output
169
            chunk = os.read(proc.stdout.fileno(), 1024)
3367.1.2 by Stuart Bishop
Don't insert random spaces in test_on_merge.py output
170
            sys.stdout.write(chunk)
3308.1.2 by Stuart Bishop
Make test_on_merge.py do incremental output
171
            if chunk == "":
3308.1.4 by Stuart Bishop
Fix test_on_merge.py incremental output
172
                open_readers.remove(proc.stdout)
3308.1.2 by Stuart Bishop
Make test_on_merge.py do incremental output
173
3308.1.4 by Stuart Bishop
Fix test_on_merge.py incremental output
174
    rv = proc.wait()
3308.1.2 by Stuart Bishop
Make test_on_merge.py do incremental output
175
    if rv == 0:
6393.2.2 by Joey Stanford
working updates since I had to change the line for pyflakes
176
        print '\nSuccessfully ran all tests.'
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
177
    else:
3308.1.2 by Stuart Bishop
Make test_on_merge.py do incremental output
178
        print '\nTests failed (exit code %d)' % rv
179
180
    return rv
181
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
182
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
183
def killem(pid, signal):
184
    """Kill the process group leader identified by pid and other group members
185
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.
186
    Note that bin/test sets its process to a process group leader.
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
187
    """
188
    try:
189
        os.killpg(os.getpgid(pid), signal)
190
    except OSError, x:
191
        if x.errno == errno.ESRCH:
192
            pass
193
        else:
194
            raise
195
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
196
if __name__ == '__main__':
197
    sys.exit(main())