~launchpad-pqm/launchpad/devel

3944.1.1 by Francis J. Lacoste
Use system version python2.4 for scripts.
1
#!/usr/bin/python2.4
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
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
3308.1.2 by Stuart Bishop
Make test_on_merge.py do incremental output
11
from subprocess import Popen, PIPE, STDOUT
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
12
from signal import SIGKILL, SIGTERM
13
from select import select
14
4107.1.9 by Stuart Bishop
Increase test_on_merge timeout to one hour
15
# Die and kill the kids if no output for 60 minutes. Tune this if if your
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
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.
4107.1.9 by Stuart Bishop
Increase test_on_merge timeout to one hour
18
TIMEOUT = 60 * 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
2976.10.114 by Stuart Bishop
Test tweaks
31
    # NB. If tabnanny raises an exception, run 
32
    # python /usr/lib/python2.4/tabnanny.py -vv lib/canonical
33
    # for more detailed output.
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
34
    org_stdout = sys.stdout
35
    sys.stdout = StringIO()
36
    tabnanny.check(os.path.join(here, 'lib', 'canonical'))
37
    tabnanny_results = sys.stdout.getvalue()
38
    sys.stdout = org_stdout
39
    if len(tabnanny_results) > 0:
40
        print '---- tabnanny bitching ----'
41
        print tabnanny_results
42
        print '---- end tabnanny bitching ----'
43
        return 1
44
1064.1.3 by James Henstridge
merge from marius
45
    # Sanity check PostgreSQL version. No point in trying to create a test
46
    # database when PostgreSQL is too old.
47
    con = psycopg.connect('dbname=template1')
48
    cur = con.cursor()
49
    cur.execute('show server_version')
50
    server_version = cur.fetchone()[0]
51
    try:
52
        numeric_server_version = tuple(map(int, server_version.split('.')))
53
    except ValueError:
54
        # Skip this check if the version number is more complicated than
55
        # we expected.
56
        pass
57
    else:
3257.1.1 by Stuart Bishop
PostgreSQL 8.0+ required
58
        if numeric_server_version < (8, 0):
59
            print 'Your PostgreSQL version is too old.  You need 8.x.x'
1064.1.3 by James Henstridge
merge from marius
60
            print 'You have %s' % server_version
61
            return 1
62
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
63
    # Drop the template database if it exists - the Makefile does this
64
    # too, but we can explicity check for errors here
65
    con = psycopg.connect('dbname=template1')
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
66
    con.set_isolation_level(0)
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
67
    cur = con.cursor()
1064.1.3 by James Henstridge
merge from marius
68
    try:
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
69
        cur.execute('drop database launchpad_ftest_template')
1520 by Canonical.com Patch Queue Manager
Review and fix database security update code
70
    except psycopg.ProgrammingError, x:
71
        if 'does not exist' not in str(x):
72
            raise
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
73
    cur.execute("""
74
        select count(*) from pg_stat_activity
75
        where datname in ('launchpad_dev',
76
            'launchpad_ftest_template', 'launchpad_ftest')
77
        """)
78
    existing_connections = cur.fetchone()[0]
79
    if existing_connections > 0:
80
        print 'Cannot rebuild database. There are %d open connections.' % (
81
                existing_connections,
82
                )
83
        return 1
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
84
    cur.close()
85
    con.close()
86
    
87
88
    # Build the template database. Tests duplicate this.
89
    here = os.path.dirname(os.path.realpath(__file__))
90
    schema_dir = os.path.join(here, 'database', 'schema')
1297 by Canonical.com Patch Queue Manager
Merge in database security branch
91
    if os.system('cd %s; make test PYTHON=%s > /dev/null' % (
1155 by Canonical.com Patch Queue Manager
More robust authentication
92
        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
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.
98
    con = psycopg.connect('dbname=launchpad_ftest_template')
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
    
133
134
    print 'Running tests.'
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
135
    os.chdir(here)
136
    cmd = [sys.executable, 'test.py'] + sys.argv[1:]
137
    print ' '.join(cmd)
4107.1.9 by Stuart Bishop
Increase test_on_merge timeout to one hour
138
139
    # Run the test suite and return the error code
140
    #return call(cmd)
141
3308.1.2 by Stuart Bishop
Make test_on_merge.py do incremental output
142
    proc = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
143
    proc.stdin.close()
144
3258.1.1 by Andrew Bennetts
Fix backwards timeout detection logic in test_on_merge.py
145
    # Do proc.communicate(), but timeout if there's no activity on stdout or
146
    # stderr for too long.
3308.1.2 by Stuart Bishop
Make test_on_merge.py do incremental output
147
    open_readers = set([proc.stdout])
3308.1.4 by Stuart Bishop
Fix test_on_merge.py incremental output
148
    while open_readers:
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
149
        rlist, wlist, xlist = select(open_readers, [], [], TIMEOUT)
150
4092.2.18 by Barry Warsaw
Respond to spiv's review:
151
        if len(rlist) == 0:
3258.1.1 by Andrew Bennetts
Fix backwards timeout detection logic in test_on_merge.py
152
            if proc.poll() is not None:
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
153
                break
4107.1.9 by Stuart Bishop
Increase test_on_merge timeout to one hour
154
            print '\nTests hung - no output for %d seconds. Killing.' % TIMEOUT
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
155
            killem(proc.pid, SIGTERM)
156
            time.sleep(3)
3258.1.1 by Andrew Bennetts
Fix backwards timeout detection logic in test_on_merge.py
157
            if proc.poll() is not None:
4107.1.9 by Stuart Bishop
Increase test_on_merge timeout to one hour
158
                print '\nNot dead yet! - slaughtering mercilessly'
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
159
                killem(proc.pid, SIGKILL)
4092.2.12 by Barry Warsaw
Thanks to jamesh, do a better job of draining the subprocess's stdout and
160
            # Drain the subprocess's stdout and stderr.
161
            sys.stdout.write(proc.stdout.read())
162
            break
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
163
164
        if proc.stdout in rlist:
3308.1.2 by Stuart Bishop
Make test_on_merge.py do incremental output
165
            chunk = os.read(proc.stdout.fileno(), 1024)
3367.1.2 by Stuart Bishop
Don't insert random spaces in test_on_merge.py output
166
            sys.stdout.write(chunk)
3308.1.2 by Stuart Bishop
Make test_on_merge.py do incremental output
167
            if chunk == "":
3308.1.4 by Stuart Bishop
Fix test_on_merge.py incremental output
168
                open_readers.remove(proc.stdout)
3308.1.2 by Stuart Bishop
Make test_on_merge.py do incremental output
169
3308.1.4 by Stuart Bishop
Fix test_on_merge.py incremental output
170
    rv = proc.wait()
3308.1.2 by Stuart Bishop
Make test_on_merge.py do incremental output
171
    if rv == 0:
172
        print '\nSuccessfully run tests.'
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
173
    else:
3308.1.2 by Stuart Bishop
Make test_on_merge.py do incremental output
174
        print '\nTests failed (exit code %d)' % rv
175
176
    return rv
177
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
178
2083 by Canonical.com Patch Queue Manager
[r=jamesh] testrunner improvements (?)
179
def killem(pid, signal):
180
    """Kill the process group leader identified by pid and other group members
181
182
    Note that test.py sets its process to a process group leader.
183
    """
184
    try:
185
        os.killpg(os.getpgid(pid), signal)
186
    except OSError, x:
187
        if x.errno == errno.ESRCH:
188
            pass
189
        else:
190
            raise
191
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
192
if __name__ == '__main__':
193
    sys.exit(main())