~launchpad-pqm/launchpad/devel

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
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
10637.3.5 by Guilherme Salgado
Revert a couple changes left by accident
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')
10303.1.15 by Gary Poster
make test_on_merge.py work, so buildbot can pass
96
    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
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)
10096.2.2 by Bjorn Tillenius
Run xvfb-run inside test_on_merge.py.
139
    cmd = [
140
        'xvfb-run',
141
        '-s',
142
        "'-screen 0 1024x768x24'",
143
        os.path.join(here, 'bin', 'test')] + sys.argv[1:]
10096.2.3 by Bjorn Tillenius
Use xvfb-run in test_on_merge.py
144
    command_line = ' '.join(cmd)
145
    print command_line
4107.1.9 by Stuart Bishop
Increase test_on_merge timeout to one hour
146
147
    # Run the test suite and return the error code
148
    #return call(cmd)
149
10096.2.3 by Bjorn Tillenius
Use xvfb-run in test_on_merge.py
150
    proc = Popen(
151
        command_line, stdin=PIPE, stdout=PIPE, stderr=STDOUT, shell=True)
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
152
    proc.stdin.close()
153
3258.1.1 by Andrew Bennetts
Fix backwards timeout detection logic in test_on_merge.py
154
    # Do proc.communicate(), but timeout if there's no activity on stdout or
155
    # stderr for too long.
3308.1.2 by Stuart Bishop
Make test_on_merge.py do incremental output
156
    open_readers = set([proc.stdout])
3308.1.4 by Stuart Bishop
Fix test_on_merge.py incremental output
157
    while open_readers:
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
158
        rlist, wlist, xlist = select(open_readers, [], [], TIMEOUT)
159
4092.2.18 by Barry Warsaw
Respond to spiv's review:
160
        if len(rlist) == 0:
3258.1.1 by Andrew Bennetts
Fix backwards timeout detection logic in test_on_merge.py
161
            if proc.poll() is not None:
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
162
                break
6393.2.2 by Joey Stanford
working updates since I had to change the line for pyflakes
163
            print ("\nA test appears to be hung. There has been no output for"
164
                " %d seconds. Sending SIGTERM." % TIMEOUT)
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
165
            killem(proc.pid, SIGTERM)
166
            time.sleep(3)
3258.1.1 by Andrew Bennetts
Fix backwards timeout detection logic in test_on_merge.py
167
            if proc.poll() is not None:
6393.2.2 by Joey Stanford
working updates since I had to change the line for pyflakes
168
                print ("\nSIGTERM did not work. Sending SIGKILL.")
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
169
                killem(proc.pid, SIGKILL)
4092.2.12 by Barry Warsaw
Thanks to jamesh, do a better job of draining the subprocess's stdout and
170
            # Drain the subprocess's stdout and stderr.
171
            sys.stdout.write(proc.stdout.read())
172
            break
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
173
174
        if proc.stdout in rlist:
3308.1.2 by Stuart Bishop
Make test_on_merge.py do incremental output
175
            chunk = os.read(proc.stdout.fileno(), 1024)
3367.1.2 by Stuart Bishop
Don't insert random spaces in test_on_merge.py output
176
            sys.stdout.write(chunk)
3308.1.2 by Stuart Bishop
Make test_on_merge.py do incremental output
177
            if chunk == "":
3308.1.4 by Stuart Bishop
Fix test_on_merge.py incremental output
178
                open_readers.remove(proc.stdout)
3308.1.2 by Stuart Bishop
Make test_on_merge.py do incremental output
179
3308.1.4 by Stuart Bishop
Fix test_on_merge.py incremental output
180
    rv = proc.wait()
3308.1.2 by Stuart Bishop
Make test_on_merge.py do incremental output
181
    if rv == 0:
6393.2.2 by Joey Stanford
working updates since I had to change the line for pyflakes
182
        print '\nSuccessfully ran all tests.'
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
183
    else:
3308.1.2 by Stuart Bishop
Make test_on_merge.py do incremental output
184
        print '\nTests failed (exit code %d)' % rv
185
186
    return rv
187
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
188
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
189
def killem(pid, signal):
190
    """Kill the process group leader identified by pid and other group members
191
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.
192
    Note that bin/test sets its process to a process group leader.
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
193
    """
194
    try:
195
        os.killpg(os.getpgid(pid), signal)
196
    except OSError, x:
197
        if x.errno == errno.ESRCH:
198
            pass
199
        else:
200
            raise
201
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
202
if __name__ == '__main__':
203
    sys.exit(main())