~launchpad-pqm/launchpad/devel

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())