~launchpad-pqm/launchpad/devel

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