Merge lp:~lifeless/launchpad/databasefixture into lp:launchpad

Proposed by Robert Collins
Status: Merged
Approved by: Robert Collins
Approved revision: no longer in the source branch.
Merged at revision: 11734
Proposed branch: lp:~lifeless/launchpad/databasefixture
Merge into: lp:launchpad
Diff against target: 1478 lines (+247/-460)
21 files modified
lib/canonical/config/tests/test_database_config.py (+10/-6)
lib/canonical/database/ftests/test_postgresql.py (+5/-3)
lib/canonical/database/ftests/test_sqlbaseconnect.txt (+2/-2)
lib/canonical/ftests/pgsql.py (+11/-30)
lib/canonical/ftests/test_pgsql.py (+60/-63)
lib/canonical/launchpad/doc/canonical-config.txt (+6/-4)
lib/canonical/launchpad/doc/old-testing.txt (+19/-127)
lib/canonical/launchpad/doc/security-proxies.txt (+0/-8)
lib/canonical/launchpad/ftests/harness.py (+0/-84)
lib/canonical/launchpad/pagetests/standalone/xx-dbpolicy.txt (+5/-3)
lib/canonical/launchpad/tests/test_sampledata.py (+2/-6)
lib/canonical/launchpad/webapp/ftests/test_adapter.txt (+6/-2)
lib/canonical/lp/ftests/test_zopeless.py (+14/-9)
lib/canonical/testing/ftests/test_layers.py (+26/-21)
lib/canonical/testing/layers.py (+53/-55)
lib/lp/codehosting/tests/test_acceptance.py (+20/-21)
lib/lp/soyuz/doc/sampledata-setup.txt (+2/-2)
lib/lp/soyuz/scripts/tests/test_buildd_cronscripts.py (+2/-3)
lib/lp/translations/doc/fix_translation_credits.txt (+2/-2)
lib/lp/translations/doc/message-sharing-merge-script.txt (+2/-2)
lib/lp/translations/doc/request_country.txt (+0/-7)
To merge this branch: bzr merge lp:~lifeless/launchpad/databasefixture
Reviewer Review Type Date Requested Status
Jonathan Lange (community) Approve
Review via email: mp+38643@code.launchpad.net

Commit message

Make database test support capable of running with unique db test names.

Description of the change

This makes the database test support layer ready for parallel testing - we can run with unique database names. Not supported yet is having the config system unique for a test process (I'd make it more granular than that, but zcml is so global that I don't think thats feasible until we reengineer that entire stack.

Some things were no longer used, so I deleted them. Most things were trivial.

We won't see any test DB leaks at this point, but I'm worried about the possibility when we turn this on... still thats a problem for another day.

To post a comment you must log in.
Revision history for this message
Jonathan Lange (jml) wrote :

On Sun, Oct 17, 2010 at 7:59 AM, Robert Collins
<email address hidden> wrote:
> Robert Collins has proposed merging lp:~lifeless/launchpad/databasefixture into lp:launchpad/devel.
>
> Requested reviews:
>  Jonathan Lange (jml)
>
>
> This makes the database test support layer ready for parallel testing - we can run with unique database names. Not supported yet is having the config system unique for a test process (I'd make it more granular than that, but zcml is so global that I don't think thats feasible until we reengineer that entire stack.
>
> Some things were no longer used, so I deleted them. Most things were trivial.
>
> We won't see any test DB leaks at this point, but I'm worried about the possibility when we turn this on... still thats a problem for another day.

As you said on IRC, it's a mostly mechanical branch. The changes all
look good to me, and definitely in the right direction.

Land when ready.

jml

Revision history for this message
Jonathan Lange (jml) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/canonical/config/tests/test_database_config.py'
--- lib/canonical/config/tests/test_database_config.py 2010-01-13 20:06:09 +0000
+++ lib/canonical/config/tests/test_database_config.py 2010-10-17 19:12:52 +0000
@@ -3,17 +3,20 @@
33
4__metaclass__ = type4__metaclass__ = type
55
6from lp.testing import TestCase
7
8from canonical.config import config, dbconfig6from canonical.config import config, dbconfig
9
10from canonical.launchpad.readonly import read_only_file_exists7from canonical.launchpad.readonly import read_only_file_exists
11from canonical.launchpad.tests.readonly import (8from canonical.launchpad.tests.readonly import (
12 remove_read_only_file, touch_read_only_file)9 remove_read_only_file,
10 touch_read_only_file,
11 )
12from canonical.testing.layers import DatabaseLayer
13from lp.testing import TestCase
1314
1415
15class TestDatabaseConfig(TestCase):16class TestDatabaseConfig(TestCase):
1617
18 layer = DatabaseLayer
19
17 def test_overlay(self):20 def test_overlay(self):
18 # The dbconfig option overlays the database configurations of a21 # The dbconfig option overlays the database configurations of a
19 # chosen config section over the base section.22 # chosen config section over the base section.
@@ -25,11 +28,12 @@
25 self.assertEquals('librarian', config.librarian.dbuser)28 self.assertEquals('librarian', config.librarian.dbuser)
2629
27 dbconfig.setConfigSection('librarian')30 dbconfig.setConfigSection('librarian')
28 self.assertEquals('dbname=launchpad_ftest', dbconfig.rw_main_master)31 expected_db = 'dbname=%s' % DatabaseLayer._db_fixture.dbname
32 self.assertEquals(expected_db, dbconfig.rw_main_master)
29 self.assertEquals('librarian', dbconfig.dbuser)33 self.assertEquals('librarian', dbconfig.dbuser)
3034
31 dbconfig.setConfigSection('launchpad')35 dbconfig.setConfigSection('launchpad')
32 self.assertEquals('dbname=launchpad_ftest', dbconfig.rw_main_master)36 self.assertEquals(expected_db, dbconfig.rw_main_master)
33 self.assertEquals('launchpad_main', dbconfig.dbuser)37 self.assertEquals('launchpad_main', dbconfig.dbuser)
3438
35 def test_required_values(self):39 def test_required_values(self):
3640
=== modified file 'lib/canonical/database/ftests/test_postgresql.py'
--- lib/canonical/database/ftests/test_postgresql.py 2010-07-14 14:11:15 +0000
+++ lib/canonical/database/ftests/test_postgresql.py 2010-10-17 19:12:52 +0000
@@ -10,8 +10,9 @@
10def setUp(test):10def setUp(test):
1111
12 # Build a fresh, empty database and connect12 # Build a fresh, empty database and connect
13 PgTestSetup().setUp()13 test._db_fixture = PgTestSetup()
14 con = PgTestSetup().connect()14 test._db_fixture.setUp()
15 con = test._db_fixture.connect()
1516
16 # Create a test schema demonstrating the edge cases17 # Create a test schema demonstrating the edge cases
17 cur = con.cursor()18 cur = con.cursor()
@@ -53,8 +54,9 @@
53 test.globs['cur'] = cur54 test.globs['cur'] = cur
5455
55def tearDown(test):56def tearDown(test):
56 PgTestSetup().tearDown()
57 test.globs['con'].close()57 test.globs['con'].close()
58 test._db_fixture.tearDown()
59 del test._db_fixture
5860
59def test_suite():61def test_suite():
60 suite = DocTestSuite(62 suite = DocTestSuite(
6163
=== modified file 'lib/canonical/database/ftests/test_sqlbaseconnect.txt'
--- lib/canonical/database/ftests/test_sqlbaseconnect.txt 2009-04-17 10:32:16 +0000
+++ lib/canonical/database/ftests/test_sqlbaseconnect.txt 2010-10-17 19:12:52 +0000
@@ -19,7 +19,7 @@
19Specifying the user connects as that user.19Specifying the user connects as that user.
2020
21 >>> do_connect(user=config.launchpad_session.dbuser)21 >>> do_connect(user=config.launchpad_session.dbuser)
22 Connected as session to launchpad_ftest in read committed isolation.22 Connected as session to ... in read committed isolation.
2323
24Specifying the database name connects to that database.24Specifying the database name connects to that database.
2525
@@ -31,5 +31,5 @@
31 >>> do_connect(31 >>> do_connect(
32 ... user=config.launchpad.dbuser,32 ... user=config.launchpad.dbuser,
33 ... isolation=ISOLATION_LEVEL_SERIALIZABLE)33 ... isolation=ISOLATION_LEVEL_SERIALIZABLE)
34 Connected as launchpad_main to launchpad_ftest in serializable isolation.34 Connected as launchpad_main to ... in serializable isolation.
3535
3636
=== modified file 'lib/canonical/ftests/pgsql.py'
--- lib/canonical/ftests/pgsql.py 2009-10-09 04:05:34 +0000
+++ lib/canonical/ftests/pgsql.py 2010-10-17 19:12:52 +0000
@@ -7,7 +7,7 @@
77
8__metaclass__ = type8__metaclass__ = type
99
10import unittest10import os
11import time11import time
1212
13import psycopg213import psycopg2
@@ -119,7 +119,6 @@
119119
120_org_connect = None120_org_connect = None
121def fake_connect(*args, **kw):121def fake_connect(*args, **kw):
122 global _org_connect
123 return ConnectionWrapper(_org_connect(*args, **kw))122 return ConnectionWrapper(_org_connect(*args, **kw))
124123
125def installFakeConnect():124def installFakeConnect():
@@ -136,9 +135,13 @@
136135
137136
138class PgTestSetup:137class PgTestSetup:
138
139 connections = [] # Shared139 connections = [] # Shared
140 # Use a dynamically generated dbname:
141 dynamic = object()
140142
141 template = 'template1'143 template = 'template1'
144 # Needs to match configs/testrunner*/*:
142 dbname = 'launchpad_ftest'145 dbname = 'launchpad_ftest'
143 dbuser = None146 dbuser = None
144 host = None147 host = None
@@ -165,8 +168,13 @@
165 '''168 '''
166 if template is not None:169 if template is not None:
167 self.template = template170 self.template = template
168 if dbname is not None:171 if dbname is PgTestSetup.dynamic:
172 self.dbname = self.__class__.dbname + "_" + str(os.getpid())
173 elif dbname is not None:
169 self.dbname = dbname174 self.dbname = dbname
175 else:
176 # Fallback to the class name.
177 self.dbname = self.__class__.dbname
170 if dbuser is not None:178 if dbuser is not None:
171 self.dbuser = dbuser179 self.dbuser = dbuser
172 if host is not None:180 if host is not None:
@@ -331,30 +339,3 @@
331 as database changes made from a subprocess.339 as database changes made from a subprocess.
332 """340 """
333 PgTestSetup._reset_db = True341 PgTestSetup._reset_db = True
334
335
336class PgTestCase(unittest.TestCase):
337 dbname = None
338 dbuser = None
339 host = None
340 port = None
341 template = None
342 def setUp(self):
343 pg_test_setup = PgTestSetup(
344 self.template, self.dbname, self.dbuser, self.host, self.port
345 )
346 pg_test_setup.setUp()
347 self.dbname = pg_test_setup.dbname
348 self.dbuser = pg_test_setup.dbuser
349 assert self.dbname, 'self.dbname is not set.'
350
351 def tearDown(self):
352 PgTestSetup(
353 self.template, self.dbname, self.dbuser, self.host, self.port
354 ).tearDown()
355
356 def connect(self):
357 return PgTestSetup(
358 self.template, self.dbname, self.dbuser, self.host, self.port
359 ).connect()
360
361342
=== modified file 'lib/canonical/ftests/test_pgsql.py'
--- lib/canonical/ftests/test_pgsql.py 2009-06-25 05:30:52 +0000
+++ lib/canonical/ftests/test_pgsql.py 2010-10-17 19:12:52 +0000
@@ -1,77 +1,84 @@
1# Copyright 2009 Canonical Ltd. This software is licensed under the1# Copyright 2009-2010 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4import unittest4import os
5from canonical.ftests.pgsql import PgTestCase, PgTestSetup, ConnectionWrapper5
66import testtools
77
8class TestPgTestCase(PgTestCase):8from canonical.ftests.pgsql import (
99 ConnectionWrapper,
10 def testRollback(self):10 PgTestSetup,
11 # This test creates a table. We run the same test twice,11 )
12 # which will fail if database changes are not rolled back12
13 con = self.connect()13
14 cur = con.cursor()14class TestPgTestSetup(testtools.TestCase):
15 cur.execute('CREATE TABLE foo (x int)')15
16 cur.execute('INSERT INTO foo VALUES (1)')16 def test_db_naming(self):
17 cur.execute('SELECT x FROM foo')17 fixture = PgTestSetup(dbname=PgTestSetup.dynamic)
18 res = list(cur.fetchall())18 expected_name = "%s_%s" % (PgTestSetup.dbname, os.getpid())
19 self.failUnless(len(res) == 1)19 self.assertEqual(expected_name, fixture.dbname)
20 self.failUnless(res[0][0] == 1)20 fixture.setUp()
21 con.commit()21 self.addCleanup(fixture.dropDb)
2222 self.addCleanup(fixture.tearDown)
23 testRollback2 = testRollback23 cur = fixture.connect().cursor()
2424 cur.execute('SELECT current_database()')
25class TestOptimization(unittest.TestCase):25 where = cur.fetchone()[0]
26 self.assertEqual(expected_name, where)
27
26 def testOptimization(self):28 def testOptimization(self):
27 # Test to ensure that the database is destroyed only when necessary29 # Test to ensure that the database is destroyed only when necessary
2830
29 # Make a change to a database31 # Make a change to a database
30 PgTestSetup().setUp()32 fixture = PgTestSetup()
33 fixture.setUp()
31 try:34 try:
32 con = PgTestSetup().connect()35 con = fixture.connect()
33 cur = con.cursor()36 cur = con.cursor()
34 cur.execute('CREATE TABLE foo (x int)')37 cur.execute('CREATE TABLE foo (x int)')
35 con.commit()38 con.commit()
36 # Fake it so the harness doesn't know a change has been made39 # Fake it so the harness doesn't know a change has been made
37 ConnectionWrapper.committed = False40 ConnectionWrapper.committed = False
38 finally:41 finally:
39 PgTestSetup().tearDown()42 fixture.tearDown()
4043
41 # Now check to ensure that the table we just created is still there44 # Now check to ensure that the table we just created is still there if
42 PgTestSetup().setUp()45 # we reuse the fixture.
46 fixture.setUp()
43 try:47 try:
44 con = PgTestSetup().connect()48 con = fixture.connect()
45 cur = con.cursor()49 cur = con.cursor()
46 # This tests that the table still exists, as well as modifying the50 # This tests that the table still exists, as well as modifying the
47 # db51 # db
48 cur.execute('INSERT INTO foo VALUES (1)')52 cur.execute('INSERT INTO foo VALUES (1)')
49 con.commit()53 con.commit()
50 finally:54 finally:
51 PgTestSetup().tearDown()55 fixture.tearDown()
5256
53 # Now ensure that the table is gone57 # Now ensure that the table is gone - the commit must have been rolled
54 PgTestSetup().setUp()58 # back.
59 fixture.setUp()
55 try:60 try:
56 con = PgTestSetup().connect()61 con = fixture.connect()
57 cur = con.cursor()62 cur = con.cursor()
58 cur.execute('CREATE TABLE foo (x int)')63 cur.execute('CREATE TABLE foo (x int)')
59 con.commit()64 con.commit()
60 ConnectionWrapper.committed = False # Leave the table65 ConnectionWrapper.committed = False # Leave the table
61 finally:66 finally:
62 PgTestSetup().tearDown()67 fixture.tearDown()
6368
64 # The database should *always* be recreated if the template69 # The database should *always* be recreated if a new template had been
65 # changes.70 # chosen.
66 PgTestSetup._last_db = ('whatever', 'launchpad_ftest')71 PgTestSetup._last_db = ('different-template', fixture.dbname)
67 PgTestSetup().setUp()72 fixture.setUp()
68 try:73 try:
69 con = PgTestSetup().connect()74 con = fixture.connect()
70 cur = con.cursor()75 cur = con.cursor()
76 # If this fails, TABLE foo still existed and the DB wasn't rebuilt
77 # correctly.
71 cur.execute('CREATE TABLE foo (x int)')78 cur.execute('CREATE TABLE foo (x int)')
72 con.commit()79 con.commit()
73 finally:80 finally:
74 PgTestSetup().tearDown()81 fixture.tearDown()
7582
76 def test_sequences(self):83 def test_sequences(self):
77 # Sequences may be affected by connections even if the connection84 # Sequences may be affected by connections even if the connection
@@ -80,9 +87,10 @@
80 # the sequences.87 # the sequences.
8188
82 # Setup a table that uses a sequence89 # Setup a table that uses a sequence
83 PgTestSetup().setUp()90 fixture = PgTestSetup()
91 fixture.setUp()
84 try:92 try:
85 con = PgTestSetup().connect()93 con = fixture.connect()
86 cur = con.cursor()94 cur = con.cursor()
87 cur.execute('CREATE TABLE foo (x serial, y integer)')95 cur.execute('CREATE TABLE foo (x serial, y integer)')
88 con.commit()96 con.commit()
@@ -90,15 +98,15 @@
90 # Fake it so the harness doesn't know a change has been made98 # Fake it so the harness doesn't know a change has been made
91 ConnectionWrapper.committed = False99 ConnectionWrapper.committed = False
92 finally:100 finally:
93 PgTestSetup().tearDown()101 fixture.tearDown()
94102
95 sequence_values = []103 sequence_values = []
96 # Insert a row into it and roll back the changes. Each time, we104 # Insert a row into it and roll back the changes. Each time, we
97 # should end up with the same sequence value105 # should end up with the same sequence value
98 for i in range(3):106 for i in range(3):
99 PgTestSetup().setUp()107 fixture.setUp()
100 try:108 try:
101 con = PgTestSetup().connect()109 con = fixture.connect()
102 cur = con.cursor()110 cur = con.cursor()
103 cur.execute('INSERT INTO foo (y) VALUES (1)')111 cur.execute('INSERT INTO foo (y) VALUES (1)')
104 cur.execute("SELECT currval('foo_x_seq')")112 cur.execute("SELECT currval('foo_x_seq')")
@@ -106,7 +114,7 @@
106 con.rollback()114 con.rollback()
107 con.close()115 con.close()
108 finally:116 finally:
109 PgTestSetup().tearDown()117 fixture.tearDown()
110118
111 # Fail if we got a diffent sequence value at some point119 # Fail if we got a diffent sequence value at some point
112 for v in sequence_values:120 for v in sequence_values:
@@ -114,9 +122,9 @@
114122
115 # Repeat the test, but this time with some data already in the123 # Repeat the test, but this time with some data already in the
116 # table124 # table
117 PgTestSetup().setUp()125 fixture.setUp()
118 try:126 try:
119 con = PgTestSetup().connect()127 con = fixture.connect()
120 cur = con.cursor()128 cur = con.cursor()
121 cur.execute('INSERT INTO foo (y) VALUES (1)')129 cur.execute('INSERT INTO foo (y) VALUES (1)')
122 con.commit()130 con.commit()
@@ -124,15 +132,15 @@
124 # Fake it so the harness doesn't know a change has been made132 # Fake it so the harness doesn't know a change has been made
125 ConnectionWrapper.committed = False133 ConnectionWrapper.committed = False
126 finally:134 finally:
127 PgTestSetup().tearDown()135 fixture.tearDown()
128136
129 sequence_values = []137 sequence_values = []
130 # Insert a row into it and roll back the changes. Each time, we138 # Insert a row into it and roll back the changes. Each time, we
131 # should end up with the same sequence value139 # should end up with the same sequence value
132 for i in range(1,3):140 for i in range(1,3):
133 PgTestSetup().setUp()141 fixture.setUp()
134 try:142 try:
135 con = PgTestSetup().connect()143 con = fixture.connect()
136 cur = con.cursor()144 cur = con.cursor()
137 cur.execute('INSERT INTO foo (y) VALUES (1)')145 cur.execute('INSERT INTO foo (y) VALUES (1)')
138 cur.execute("SELECT currval('foo_x_seq')")146 cur.execute("SELECT currval('foo_x_seq')")
@@ -140,19 +148,8 @@
140 con.rollback()148 con.rollback()
141 con.close()149 con.close()
142 finally:150 finally:
143 PgTestSetup().tearDown()151 fixture.tearDown()
144152
145 # Fail if we got a diffent sequence value at some point153 # Fail if we got a diffent sequence value at some point
146 for v in sequence_values:154 for v in sequence_values:
147 self.failUnlessEqual(v, sequence_values[0])155 self.failUnlessEqual(v, sequence_values[0])
148
149
150def test_suite():
151 suite = unittest.TestSuite()
152 suite.addTest(unittest.makeSuite(TestPgTestCase))
153 suite.addTest(unittest.makeSuite(TestOptimization))
154 return suite
155
156if __name__ == '__main__':
157 unittest.main()
158
159156
=== modified file 'lib/canonical/launchpad/doc/canonical-config.txt'
--- lib/canonical/launchpad/doc/canonical-config.txt 2010-01-05 19:09:58 +0000
+++ lib/canonical/launchpad/doc/canonical-config.txt 2010-10-17 19:12:52 +0000
@@ -14,8 +14,10 @@
14simple configuration).14simple configuration).
1515
16 >>> from canonical.config import config16 >>> from canonical.config import config
17 >>> print config.database.rw_main_master17 >>> from canonical.testing.layers import DatabaseLayer
18 dbname=launchpad_ftest18 >>> expected = 'dbname=%s' % DatabaseLayer._db_fixture.dbname
19 >>> expected == config.database.rw_main_master
20 True
19 >>> config.database.db_statement_timeout is None21 >>> config.database.db_statement_timeout is None
20 True22 True
21 >>> config.launchpad.dbuser23 >>> config.launchpad.dbuser
@@ -226,7 +228,7 @@
226# >>> canonical.config.config = config228# >>> canonical.config.config = config
227# >>> config.filename229# >>> config.filename
228# '.../configs/testrunner/launchpad-lazr.conf'230# '.../configs/testrunner/launchpad-lazr.conf'
229# >>> config.dbname231# >>> config.dbname == DatabaseLayer._db_fixture.dbname
230# 'launchpad_ftest'232# True
231# >>> config._cache.testrunner233# >>> config._cache.testrunner
232# <SectionValue for canonical 'testrunner'>234# <SectionValue for canonical 'testrunner'>
233235
=== modified file 'lib/canonical/launchpad/doc/old-testing.txt'
--- lib/canonical/launchpad/doc/old-testing.txt 2010-10-03 20:23:37 +0000
+++ lib/canonical/launchpad/doc/old-testing.txt 2010-10-17 19:12:52 +0000
@@ -18,11 +18,6 @@
18zope, we should not be testing it with the full Z3 functional test18zope, we should not be testing it with the full Z3 functional test
19harness).19harness).
2020
21If you are wondering why we use `PgTestSetup().setUp()` and
22`PgTestSetup.tearDown()` instead of `pgtestsetup.setUp()` or
23`pgtestsetup.tearDown()`, it is because I'm mirroring the design used in
24Zope3's `FunctionalTestSetup`.
25
26canonical.functional.FunctionalTestCase21canonical.functional.FunctionalTestCase
27---------------------------------------22---------------------------------------
2823
@@ -42,11 +37,12 @@
4237
43The setup procedure builds us a fresh, empty database38The setup procedure builds us a fresh, empty database
4439
45>>> PgTestSetup().setUp()40>>> fixture = PgTestSetup()
41>>> fixture.setUp()
4642
47We can get connections to this database43We can get connections to this database
4844
49>>> connection = PgTestSetup().connect()45>>> connection = fixture.connect()
50>>> cursor = connection.cursor()46>>> cursor = connection.cursor()
51>>> cursor.execute("""CREATE TABLE Beer (47>>> cursor.execute("""CREATE TABLE Beer (
52... id serial PRIMARY KEY, name text, stamp timestamp without time zone48... id serial PRIMARY KEY, name text, stamp timestamp without time zone
@@ -68,28 +64,29 @@
68When we have finished, we need to call the tearDown method which closes64When we have finished, we need to call the tearDown method which closes
69all outstanding connections and destroys the database65all outstanding connections and destroys the database
7066
71>>> PgTestSetup().tearDown()67>>> fixture.tearDown()
7268
73Because the database has been destroyed, further tests will not be69Because the database has been destroyed, further tests will not be
74affected.70affected.
7571
76>>> PgTestSetup().setUp()72>>> fixture.setUp()
77>>> connection = PgTestSetup().connect()73>>> connection = fixture.connect()
78>>> cursor = connection.cursor()74>>> cursor = connection.cursor()
79>>> cursor.execute("CREATE TABLE Beer (id serial PRIMARY KEY, name text)")75>>> cursor.execute("CREATE TABLE Beer (id serial PRIMARY KEY, name text)")
80>>> PgTestSetup().tearDown()76>>> fixture.tearDown()
8177
82We can also specify a different template to duplicate than the default78We can also specify a different template to duplicate than the default
83clean one (template1). For example, if you need a launchpad database79clean one (template1). For example, if you need a launchpad database
84containing no data, you can use `launchpad_empty` as the template.80containing no data, you can use `launchpad_empty` as the template.
8581
86>>> PgTestSetup('launchpad_empty').setUp()82>>> fixture = PgTestSetup('launchpad_empty')
87>>> connection = PgTestSetup().connect()83>>> fixture.setUp()
84>>> connection = fixture.connect()
88>>> cursor = connection.cursor()85>>> cursor = connection.cursor()
89>>> cursor.execute("SELECT COUNT(*) FROM Person")86>>> cursor.execute("SELECT COUNT(*) FROM Person")
90>>> int(cursor.fetchone()[0])87>>> int(cursor.fetchone()[0])
910880
92>>> PgTestSetup().tearDown()89>>> fixture.tearDown()
9390
94We can also specify the user that we connect as to avoid connecting as the91We can also specify the user that we connect as to avoid connecting as the
95PostgreSQL default user.92PostgreSQL default user.
@@ -108,14 +105,12 @@
108------------------105------------------
109106
110LaunchpadTestSetup is identical to PgTestSetup, except that it creates a107LaunchpadTestSetup is identical to PgTestSetup, except that it creates a
111fresh copy of the Launchpad database filled with our sample data. This108fresh copy of the Launchpad database filled with our sample data.
112class is defined in canonical.launchpad.ftests.harness.109
113110>>> from canonical.testing.layers import LaunchpadTestSetup
114Note that at this level, you cannot access any of the SQLBase objects111>>> fixture = LaunchpadTestSetup()
115112>>> fixture.setUp()
116>>> from canonical.launchpad.ftests.harness import LaunchpadTestSetup113>>> connection = fixture.connect()
117>>> LaunchpadTestSetup().setUp()
118>>> connection = LaunchpadTestSetup().connect()
119>>> cursor = connection.cursor()114>>> cursor = connection.cursor()
120>>> cursor.execute("SELECT displayname FROM person WHERE name='carlos'")115>>> cursor.execute("SELECT displayname FROM person WHERE name='carlos'")
121>>> cursor.fetchone()[0]116>>> cursor.fetchone()[0]
@@ -127,7 +122,7 @@
127>>> cursor.fetchone()[0]122>>> cursor.fetchone()[0]
128u'launchpad'123u'launchpad'
129124
130>>> LaunchpadTestSetup().tearDown()125>>> fixture.tearDown()
131126
132You can connect as a different database user using the same mechanism127You can connect as a different database user using the same mechanism
133described above for PgTestSetup128described above for PgTestSetup
@@ -143,114 +138,13 @@
143>>> lpsetup.tearDown()138>>> lpsetup.tearDown()
144139
145140
146LaunchpadZopelessTestSetup
147--------------------------
148
149LaunchpadZopelessTestSetup builds on LaunchpadTestSetup, calling
150initZopeless for you so you can access the SQLBase objects without needing
151the Zope3 infrastructure.
152
153>>> from canonical.launchpad.ftests.harness import LaunchpadZopelessTestSetup
154>>> LaunchpadZopelessTestSetup().setUp()
155>>> from lp.registry.model.person import Person
156>>> stub = Person.byName('stub')
157>>> stub.displayname
158u'Stuart Bishop'
159>>> stub.displayname = u'The Walrus'
160>>> stub.displayname
161u'The Walrus'
162
163You have access to the zopeless transaction
164
165>>> LaunchpadZopelessTestSetup().txn.abort()
166>>> stub.displayname
167u'Stuart Bishop'
168
169And always remember to tearDown or you will victimize other tests!
170
171>>> LaunchpadZopelessTestSetup().tearDown()
172
173
174In general, Zopeless tests should never be running as the launchpad user.
175You can select the user you connect as:
176
177>>> setup = LaunchpadZopelessTestSetup(dbuser=config.librarian.dbuser)
178>>> setup.setUp()
179>>> from lp.registry.model.sourcepackagename import SourcePackageName
180>>> SourcePackageName.get(1).name
181Traceback (most recent call last):
182...
183ProgrammingError: permission denied for relation sourcepackagename
184<BLANKLINE>
185>>> setup.tearDown()
186
187
188LaunchpadFunctionalTestSetup
189----------------------------
190
191One with the lot. A LaunchpadTestSetup which also loads in the Zope3
192environment.
193
194>>> from canonical.launchpad.ftests.harness import LaunchpadFunctionalTestSetup
195>>> LaunchpadFunctionalTestSetup().setUp()
196
197You have full access to the SQLBase objects
198
199>>> mark = Person.byName('mark')
200>>> mark.displayname
201u'Mark Shuttleworth'
202
203You also have access to the Zope3 component architecture, as registered
204by ftesting.zcml
205
206>>> from zope.app import zapi
207>>> from zope.sendmail.interfaces import IMailer
208>>> zapi.getUtility(IMailer, 'smtp') is not None
209True
210
211>>> LaunchpadFunctionalTestSetup().tearDown()
212
213You can change the user that the tests connect as:
214
215 XXX 2008-05-29 jamesh:
216 Using LaunchpadFunctionalLayer for non-webapp db users is generally
217 a sign of a bug. These bits of code should generally be using
218 LaunchpadZopelessLayer.
219
220##>>> setup = LaunchpadFunctionalTestSetup(dbuser=config.librarian.dbuser)
221##>>> setup.setUp()
222##>>> connection = setup.connect()
223##>>> cursor = connection.cursor()
224##>>> cursor.execute('SELECT current_user')
225##>>> cursor.fetchone()[0]
226##u'librarian'
227##>>> SourcePackageName.get(1).name
228##Traceback (most recent call last):
229##...
230##ProgrammingError: permission denied ...
231##>>> setup.tearDown()
232
233And the next test will be unaffected:
234
235>>> setup = LaunchpadFunctionalTestSetup()
236>>> setup.setUp()
237>>> connection = setup.connect()
238>>> cursor = connection.cursor()
239>>> cursor.execute('SELECT current_user')
240>>> cursor.fetchone()[0]
241u'launchpad'
242>>> SourcePackageName.get(1).name
243u'mozilla-firefox'
244>>> setup.tearDown()
245
246
247LibrarianTestSetup141LibrarianTestSetup
248------------------142------------------
249143
250Code that needs to access the Librarian can do so easily. Note that144Code that needs to access the Librarian can do so easily. Note that
251LibrarianTestSetup requires the Launchpad database to be available, and145LibrarianTestSetup requires the Launchpad database to be available, and
252thus requires LaunchpadTestSetup or similar to be used in tandam.146thus requires LaunchpadTestSetup or similar to be used in tandam.
253You probably really want LaunchpadFunctionalTestSetup so you can access147You probably really want LaunchpadFunctionalLayer so you can access
254the Librarian as a Utility.148the Librarian as a Utility.
255149
256>>> from canonical.librarian.testing.server import LibrarianTestSetup150>>> from canonical.librarian.testing.server import LibrarianTestSetup
@@ -259,7 +153,6 @@
259>>> from canonical.librarian.interfaces import ILibrarianClient153>>> from canonical.librarian.interfaces import ILibrarianClient
260>>> from StringIO import StringIO154>>> from StringIO import StringIO
261155
262>>> LaunchpadFunctionalTestSetup().setUp()
263>>> librarian = LibrarianTestSetup()156>>> librarian = LibrarianTestSetup()
264>>> librarian.setUp()157>>> librarian.setUp()
265>>> login(ANONYMOUS)158>>> login(ANONYMOUS)
@@ -285,7 +178,6 @@
285True178True
286179
287>>> librarian.tearDown()180>>> librarian.tearDown()
288>>> LaunchpadFunctionalTestSetup().tearDown()
289181
290>>> from canonical.testing import reset_logging182>>> from canonical.testing import reset_logging
291>>> reset_logging()183>>> reset_logging()
292184
=== modified file 'lib/canonical/launchpad/doc/security-proxies.txt'
--- lib/canonical/launchpad/doc/security-proxies.txt 2010-10-09 16:36:22 +0000
+++ lib/canonical/launchpad/doc/security-proxies.txt 2010-10-17 19:12:52 +0000
@@ -6,13 +6,10 @@
66
7First, some imports and set up::7First, some imports and set up::
88
9 >>> from canonical.launchpad.ftests.harness import LaunchpadFunctionalTestSetup
10 >>> from zope.component import getUtility9 >>> from zope.component import getUtility
11 >>> from lp.registry.interfaces.person import IPersonSet10 >>> from lp.registry.interfaces.person import IPersonSet
12 >>> from lp.registry.model.person import Person11 >>> from lp.registry.model.person import Person
1312
14 >>> LaunchpadFunctionalTestSetup().setUp()
15
16Get a proxied and unproxied person object for the same person, and demonstrate13Get a proxied and unproxied person object for the same person, and demonstrate
17working comparisons::14working comparisons::
1815
@@ -57,8 +54,3 @@
57 True54 True
58 >>> hoary.status is SeriesStatus.DEVELOPMENT55 >>> hoary.status is SeriesStatus.DEVELOPMENT
59 False56 False
60
61Finally, tear down the test:
62
63 >>> LaunchpadFunctionalTestSetup().tearDown()
64
6557
=== removed file 'lib/canonical/launchpad/ftests/harness.py'
--- lib/canonical/launchpad/ftests/harness.py 2010-10-04 19:50:45 +0000
+++ lib/canonical/launchpad/ftests/harness.py 1970-01-01 00:00:00 +0000
@@ -1,84 +0,0 @@
1# Copyright 2009 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4"""
5Launchpad functional test helpers.
6
7This file needs to be refactored, moving its functionality into
8canonical.testing
9"""
10
11__metaclass__ = type
12
13
14from zope.app.testing.functional import FunctionalTestSetup
15
16from canonical.database.sqlbase import ZopelessTransactionManager
17from canonical.ftests.pgsql import PgTestSetup
18from canonical.lp import initZopeless
19from canonical.testing.layers import (
20 FunctionalLayer,
21 ZopelessLayer,
22 )
23from canonical.testing.layers import (
24 disconnect_stores,
25 reconnect_stores,
26 )
27
28
29__all__ = [
30 'LaunchpadTestSetup', 'LaunchpadZopelessTestSetup',
31 'LaunchpadFunctionalTestSetup',
32 ]
33
34
35class LaunchpadTestSetup(PgTestSetup):
36 template = 'launchpad_ftest_template'
37 dbname = 'launchpad_ftest' # Needs to match ftesting.zcml
38 dbuser = 'launchpad'
39
40
41class LaunchpadZopelessTestSetup(LaunchpadTestSetup):
42 txn = ZopelessTransactionManager
43 def setUp(self, dbuser=None):
44 assert ZopelessTransactionManager._installed is None, \
45 'Last test using Zopeless failed to tearDown correctly'
46 super(LaunchpadZopelessTestSetup, self).setUp()
47 if self.host is not None:
48 raise NotImplementedError('host not supported yet')
49 if self.port is not None:
50 raise NotImplementedError('port not supported yet')
51 if dbuser is not None:
52 self.dbuser = dbuser
53 initZopeless(dbname=self.dbname, dbuser=self.dbuser)
54
55 def tearDown(self):
56 LaunchpadZopelessTestSetup.txn.uninstall()
57 assert ZopelessTransactionManager._installed is None, \
58 'Failed to tearDown Zopeless correctly'
59
60
61class LaunchpadFunctionalTestSetup(LaunchpadTestSetup):
62 def _checkLayerInvariants(self):
63 assert FunctionalLayer.isSetUp or ZopelessLayer.isSetUp, """
64 FunctionalTestSetup invoked at an inappropriate time.
65 May only be invoked in the FunctionalLayer or ZopelessLayer
66 """
67
68 def setUp(self, dbuser=None):
69 self._checkLayerInvariants()
70 if dbuser is not None:
71 self.dbuser = dbuser
72 assert self.dbuser == 'launchpad', (
73 "Non-default user names should probably be using "
74 "script layer or zopeless layer.")
75 disconnect_stores()
76 super(LaunchpadFunctionalTestSetup, self).setUp()
77 FunctionalTestSetup().setUp()
78 reconnect_stores()
79
80 def tearDown(self):
81 self._checkLayerInvariants()
82 FunctionalTestSetup().tearDown()
83 disconnect_stores()
84 super(LaunchpadFunctionalTestSetup, self).tearDown()
850
=== modified file 'lib/canonical/launchpad/pagetests/standalone/xx-dbpolicy.txt'
--- lib/canonical/launchpad/pagetests/standalone/xx-dbpolicy.txt 2010-01-13 13:50:39 +0000
+++ lib/canonical/launchpad/pagetests/standalone/xx-dbpolicy.txt 2010-10-17 19:12:52 +0000
@@ -20,9 +20,11 @@
20 >>> from zope.component import getUtility20 >>> from zope.component import getUtility
21 >>> from canonical.launchpad.webapp.interfaces import (21 >>> from canonical.launchpad.webapp.interfaces import (
22 ... IStoreSelector, MAIN_STORE, MASTER_FLAVOR, SLAVE_FLAVOR)22 ... IStoreSelector, MAIN_STORE, MASTER_FLAVOR, SLAVE_FLAVOR)
23 >>> from canonical.testing.layers import DatabaseLayer
23 >>> master = getUtility(IStoreSelector).get(MAIN_STORE, MASTER_FLAVOR)24 >>> master = getUtility(IStoreSelector).get(MAIN_STORE, MASTER_FLAVOR)
24 >>> master.execute("SELECT current_database()").get_one()[0]25 >>> dbname = DatabaseLayer._db_fixture.dbname
25 u'launchpad_ftest'26 >>> dbname == master.execute("SELECT current_database()").get_one()[0]
27 True
26 >>> slave = getUtility(IStoreSelector).get(MAIN_STORE, SLAVE_FLAVOR)28 >>> slave = getUtility(IStoreSelector).get(MAIN_STORE, SLAVE_FLAVOR)
27 >>> slave.execute("SELECT current_database()").get_one()[0]29 >>> slave.execute("SELECT current_database()").get_one()[0]
28 u'launchpad_empty'30 u'launchpad_empty'
@@ -47,7 +49,7 @@
4749
48 >>> def whichdb(browser):50 >>> def whichdb(browser):
49 ... dbname = extract_text(find_tag_by_id(browser.contents, 'dbname'))51 ... dbname = extract_text(find_tag_by_id(browser.contents, 'dbname'))
50 ... if dbname == 'launchpad_ftest':52 ... if dbname == DatabaseLayer._db_fixture.dbname:
51 ... return 'MASTER'53 ... return 'MASTER'
52 ... elif dbname == 'launchpad_empty':54 ... elif dbname == 'launchpad_empty':
53 ... return 'SLAVE'55 ... return 'SLAVE'
5456
=== modified file 'lib/canonical/launchpad/tests/test_sampledata.py'
--- lib/canonical/launchpad/tests/test_sampledata.py 2010-09-22 13:26:50 +0000
+++ lib/canonical/launchpad/tests/test_sampledata.py 2010-10-17 19:12:52 +0000
@@ -12,7 +12,6 @@
12__all__ = []12__all__ = []
1313
14import subprocess14import subprocess
15import unittest
1615
17from canonical.testing.layers import DatabaseLayer16from canonical.testing.layers import DatabaseLayer
18from lp.testing import TestCase17from lp.testing import TestCase
@@ -37,14 +36,11 @@
37 cmd = (36 cmd = (
38 "pg_dump --format=c --compress=0 --no-privileges --no-owner"37 "pg_dump --format=c --compress=0 --no-privileges --no-owner"
39 " --schema=public %s | pg_restore --clean"38 " --schema=public %s | pg_restore --clean"
40 " --exit-on-error --dbname=launchpad_ftest" % source_dbname)39 " --exit-on-error --dbname=%s" % (
40 source_dbname, DatabaseLayer._db_fixture.dbname))
41 proc = subprocess.Popen(41 proc = subprocess.Popen(
42 cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,42 cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
43 stdin=subprocess.PIPE)43 stdin=subprocess.PIPE)
44 (stdout, stderr) = proc.communicate()44 (stdout, stderr) = proc.communicate()
45 rv = proc.wait()45 rv = proc.wait()
46 self.failUnlessEqual(rv, 0, "Dump/Restore failed: %s" % stdout)46 self.failUnlessEqual(rv, 0, "Dump/Restore failed: %s" % stdout)
47
48
49def test_suite():
50 return unittest.TestLoader().loadTestsFromName(__name__)
5147
=== modified file 'lib/canonical/launchpad/webapp/ftests/test_adapter.txt'
--- lib/canonical/launchpad/webapp/ftests/test_adapter.txt 2010-09-17 00:53:33 +0000
+++ lib/canonical/launchpad/webapp/ftests/test_adapter.txt 2010-10-17 19:12:52 +0000
@@ -18,14 +18,18 @@
18 >>> from canonical.launchpad.webapp.adapter import (18 >>> from canonical.launchpad.webapp.adapter import (
19 ... clear_request_started, get_request_statements,19 ... clear_request_started, get_request_statements,
20 ... set_request_started)20 ... set_request_started)
21 >>> from canonical.testing.layers import DatabaseLayer
21 >>> from lp.services.timeline.requesttimeline import get_request_timeline22 >>> from lp.services.timeline.requesttimeline import get_request_timeline
2223
23There are several possible database connections available via the24There are several possible database connections available via the
24IStoreSelector utility.25IStoreSelector utility.
2526
26 >>> store = getUtility(IStoreSelector).get(MAIN_STORE, MASTER_FLAVOR)27 >>> store = getUtility(IStoreSelector).get(MAIN_STORE, MASTER_FLAVOR)
27 >>> print store.execute("SELECT current_database()").get_one()[0]28 >>> dbname = DatabaseLayer._db_fixture.dbname
28 launchpad_ftest29 >>> active_name = store.execute("SELECT current_database()").get_one()[0]
30 >>> if active_name != dbname: print '%s != %s' % (active_name, dbname)
31 >>> active_name == dbname
32 True
2933
3034
31Statement Logging35Statement Logging
3236
=== modified file 'lib/canonical/lp/ftests/test_zopeless.py'
--- lib/canonical/lp/ftests/test_zopeless.py 2010-10-04 19:50:45 +0000
+++ lib/canonical/lp/ftests/test_zopeless.py 2010-10-17 19:12:52 +0000
@@ -14,9 +14,11 @@
14from sqlobject import StringCol, IntCol14from sqlobject import StringCol, IntCol
1515
16from canonical.database.sqlbase import SQLBase, alreadyInstalledMsg, cursor16from canonical.database.sqlbase import SQLBase, alreadyInstalledMsg, cursor
17from canonical.ftests.pgsql import PgTestSetup
18from canonical.lp import initZopeless17from canonical.lp import initZopeless
19from canonical.testing.layers import LaunchpadScriptLayer18from canonical.testing.layers import (
19 DatabaseLayer,
20 LaunchpadScriptLayer,
21 )
2022
2123
22class MoreBeer(SQLBase):24class MoreBeer(SQLBase):
@@ -28,6 +30,7 @@
2830
2931
30class TestInitZopeless(unittest.TestCase):32class TestInitZopeless(unittest.TestCase):
33
31 layer = LaunchpadScriptLayer34 layer = LaunchpadScriptLayer
3235
33 def test_initZopelessTwice(self):36 def test_initZopelessTwice(self):
@@ -47,10 +50,11 @@
47 # Calling initZopeless with the same arguments twice should return50 # Calling initZopeless with the same arguments twice should return
48 # the exact same object twice, but also emit a warning.51 # the exact same object twice, but also emit a warning.
49 try:52 try:
50 tm1 = initZopeless(dbname=PgTestSetup().dbname, dbhost='',53 dbname = DatabaseLayer._db_fixture.dbname
51 dbuser='launchpad')54 tm1 = initZopeless(
52 tm2 = initZopeless(dbname=PgTestSetup().dbname, dbhost='',55 dbname=dbname, dbhost='', dbuser='launchpad')
53 dbuser='launchpad')56 tm2 = initZopeless(
57 dbname=dbname, dbhost='', dbuser='launchpad')
54 self.failUnless(tm1 is tm2)58 self.failUnless(tm1 is tm2)
55 self.failUnless(self.warned)59 self.failUnless(self.warned)
56 finally:60 finally:
@@ -65,10 +69,11 @@
6569
6670
67class TestZopeless(unittest.TestCase):71class TestZopeless(unittest.TestCase):
72
68 layer = LaunchpadScriptLayer73 layer = LaunchpadScriptLayer
6974
70 def setUp(self):75 def setUp(self):
71 self.tm = initZopeless(dbname=PgTestSetup().dbname,76 self.tm = initZopeless(dbname=DatabaseLayer._db_fixture.dbname,
72 dbuser='launchpad')77 dbuser='launchpad')
7378
74 c = cursor()79 c = cursor()
@@ -182,7 +187,7 @@
182 self.tm.commit()187 self.tm.commit()
183188
184 # Make another change from a non-SQLObject connection, and commit that189 # Make another change from a non-SQLObject connection, and commit that
185 conn = psycopg2.connect('dbname=' + PgTestSetup().dbname)190 conn = psycopg2.connect('dbname=' + DatabaseLayer._db_fixture.dbname)
186 cur = conn.cursor()191 cur = conn.cursor()
187 cur.execute("BEGIN TRANSACTION;")192 cur.execute("BEGIN TRANSACTION;")
188 cur.execute("UPDATE MoreBeer SET rating=4 "193 cur.execute("UPDATE MoreBeer SET rating=4 "
@@ -202,7 +207,7 @@
202 >>> isZopeless()207 >>> isZopeless()
203 False208 False
204209
205 >>> tm = initZopeless(dbname=PgTestSetup().dbname,210 >>> tm = initZopeless(dbname=DatabaseLayer._db_fixture.dbname,
206 ... dbhost='', dbuser='launchpad')211 ... dbhost='', dbuser='launchpad')
207 >>> isZopeless()212 >>> isZopeless()
208 True213 True
209214
=== modified file 'lib/canonical/testing/ftests/test_layers.py'
--- lib/canonical/testing/ftests/test_layers.py 2010-07-26 13:18:18 +0000
+++ lib/canonical/testing/ftests/test_layers.py 2010-10-17 19:12:52 +0000
@@ -20,16 +20,27 @@
20from zope.component import getUtility, ComponentLookupError20from zope.component import getUtility, ComponentLookupError
2121
22from canonical.config import config, dbconfig22from canonical.config import config, dbconfig
23from canonical.launchpad.ftests.harness import LaunchpadTestSetup
24from lazr.config import as_host_port23from lazr.config import as_host_port
25from canonical.librarian.client import LibrarianClient, UploadFailed24from canonical.librarian.client import LibrarianClient, UploadFailed
26from canonical.librarian.interfaces import ILibrarianClient25from canonical.librarian.interfaces import ILibrarianClient
27from canonical.lazr.pidfile import pidfile_path26from canonical.lazr.pidfile import pidfile_path
28from canonical.testing.layers import (27from canonical.testing.layers import (
29 AppServerLayer, BaseLayer, DatabaseLayer, FunctionalLayer,28 AppServerLayer,
30 LaunchpadFunctionalLayer, LaunchpadLayer, LaunchpadScriptLayer,29 BaseLayer,
31 LaunchpadZopelessLayer, LayerInvariantError, LayerIsolationError,30 DatabaseLayer,
32 LayerProcessController, LibrarianLayer, MemcachedLayer, ZopelessLayer)31 FunctionalLayer,
32 LaunchpadFunctionalLayer,
33 LaunchpadLayer,
34 LaunchpadScriptLayer,
35 LaunchpadTestSetup,
36 LaunchpadZopelessLayer,
37 LayerInvariantError,
38 LayerIsolationError,
39 LayerProcessController,
40 LibrarianLayer,
41 MemcachedLayer,
42 ZopelessLayer,
43 )
33from lp.services.memcache.client import memcache_client_factory44from lp.services.memcache.client import memcache_client_factory
3445
35class BaseTestCase(unittest.TestCase):46class BaseTestCase(unittest.TestCase):
@@ -123,22 +134,13 @@
123 )134 )
124135
125 def testLaunchpadDbAvailable(self):136 def testLaunchpadDbAvailable(self):
126 try:137 if not self.want_launchpad_database:
127 con = DatabaseLayer.connect()138 self.assertEqual(None, DatabaseLayer._db_fixture)
128 cur = con.cursor()139 return
129 cur.execute("SELECT id FROM Person LIMIT 1")140 con = DatabaseLayer.connect()
130 if cur.fetchone() is not None:141 cur = con.cursor()
131 self.failUnless(142 cur.execute("SELECT id FROM Person LIMIT 1")
132 self.want_launchpad_database,143 self.assertNotEqual(None, cur.fetchone())
133 'Launchpad database should not be available.'
134 )
135 return
136 except psycopg2.Error:
137 pass
138 self.failIf(
139 self.want_launchpad_database,
140 'Launchpad database should be available but is not.'
141 )
142144
143 def testMemcachedWorking(self):145 def testMemcachedWorking(self):
144 client = MemcachedLayer.client or memcache_client_factory()146 client = MemcachedLayer.client or memcache_client_factory()
@@ -424,6 +426,9 @@
424 # The database should be reset by the test invariants.426 # The database should be reset by the test invariants.
425 LayerProcessController.startAppServer()427 LayerProcessController.startAppServer()
426 LayerProcessController.postTestInvariants()428 LayerProcessController.postTestInvariants()
429 # XXX: Robert Collins 2010-10-17 bug=661967 - this isn't a reset, its
430 # a flag that it *needs* a reset, which is actually quite different;
431 # the lack of a teardown will leak daabases.
427 self.assertEquals(True, LaunchpadTestSetup()._reset_db)432 self.assertEquals(True, LaunchpadTestSetup()._reset_db)
428433
429434
430435
=== modified file 'lib/canonical/testing/layers.py'
--- lib/canonical/testing/layers.py 2010-10-05 13:25:01 +0000
+++ lib/canonical/testing/layers.py 2010-10-17 19:12:52 +0000
@@ -35,6 +35,7 @@
35 'LaunchpadFunctionalLayer',35 'LaunchpadFunctionalLayer',
36 'LaunchpadLayer',36 'LaunchpadLayer',
37 'LaunchpadScriptLayer',37 'LaunchpadScriptLayer',
38 'LaunchpadTestSetup',
38 'LaunchpadZopelessLayer',39 'LaunchpadZopelessLayer',
39 'LayerInvariantError',40 'LayerInvariantError',
40 'LayerIsolationError',41 'LayerIsolationError',
@@ -92,6 +93,7 @@
92from zope.server.logger.pythonlogger import PythonLogger93from zope.server.logger.pythonlogger import PythonLogger
93from zope.testing.testrunner.runner import FakeInputContinueGenerator94from zope.testing.testrunner.runner import FakeInputContinueGenerator
9495
96from canonical.ftests.pgsql import PgTestSetup
95from canonical.launchpad.webapp.vhosts import allvhosts97from canonical.launchpad.webapp.vhosts import allvhosts
96from canonical.lazr import pidfile98from canonical.lazr import pidfile
97from canonical.config import CanonicalConfig, config, dbconfig99from canonical.config import CanonicalConfig, config, dbconfig
@@ -264,12 +266,14 @@
264 if not BaseLayer.persist_test_services:266 if not BaseLayer.persist_test_services:
265 kill_by_pidfile(MemcachedLayer.getPidFile(), num_polls=0)267 kill_by_pidfile(MemcachedLayer.getPidFile(), num_polls=0)
266 # Kill any database left lying around from a previous test run.268 # Kill any database left lying around from a previous test run.
269 db_fixture = LaunchpadTestSetup()
267 try:270 try:
268 DatabaseLayer.connect().close()271 db_fixture.connect().close()
269 except psycopg2.Error:272 except psycopg2.Error:
273 # We assume this means 'no test database exists.'
270 pass274 pass
271 else:275 else:
272 DatabaseLayer._dropDb()276 db_fixture.dropDb()
273277
274 @classmethod278 @classmethod
275 @profiled279 @profiled
@@ -693,19 +697,19 @@
693 _reset_between_tests = True697 _reset_between_tests = True
694698
695 _is_setup = False699 _is_setup = False
700 _db_fixture = None
696701
697 @classmethod702 @classmethod
698 @profiled703 @profiled
699 def setUp(cls):704 def setUp(cls):
700 cls._is_setup = True705 cls._is_setup = True
701 DatabaseLayer.force_dirty_database()706 # Read the sequences we'll need from the test template database.
702 # Imported here to avoid circular import issues. This707 reset_sequences_sql = LaunchpadTestSetup(
703 # functionality should be migrated into this module at some
704 # point. -- StuartBishop 20060712
705 from canonical.launchpad.ftests.harness import LaunchpadTestSetup
706 LaunchpadTestSetup().tearDown()
707 DatabaseLayer._reset_sequences_sql = LaunchpadTestSetup(
708 dbname='launchpad_ftest_template').generateResetSequencesSQL()708 dbname='launchpad_ftest_template').generateResetSequencesSQL()
709 cls._db_fixture = LaunchpadTestSetup(
710 reset_sequences_sql=reset_sequences_sql)
711 cls.force_dirty_database()
712 cls._db_fixture.tearDown()
709713
710 @classmethod714 @classmethod
711 @profiled715 @profiled
@@ -716,32 +720,22 @@
716 # Don't leave the DB lying around or it might break tests720 # Don't leave the DB lying around or it might break tests
717 # that depend on it not being there on startup, such as found721 # that depend on it not being there on startup, such as found
718 # in test_layers.py722 # in test_layers.py
719 DatabaseLayer.force_dirty_database()723 cls.force_dirty_database()
720 # Imported here to avoid circular import issues. This724 cls._db_fixture.tearDown()
721 # functionality should be migrated into this module at some725 cls._db_fixture = None
722 # point. -- StuartBishop 20060712
723 from canonical.launchpad.ftests.harness import LaunchpadTestSetup
724 LaunchpadTestSetup().tearDown()
725 DatabaseLayer._reset_sequences_sql = None
726726
727 @classmethod727 @classmethod
728 @profiled728 @profiled
729 def testSetUp(cls):729 def testSetUp(cls):
730 # Imported here to avoid circular import issues. This730 if cls._reset_between_tests:
731 # functionality should be migrated into this module at some731 cls._db_fixture.setUp()
732 # point. -- StuartBishop 20060712
733 from canonical.launchpad.ftests.harness import LaunchpadTestSetup
734 if DatabaseLayer._reset_between_tests:
735 LaunchpadTestSetup(
736 reset_sequences_sql=DatabaseLayer._reset_sequences_sql
737 ).setUp()
738 # Ensure that the database is connectable. Because we might have732 # Ensure that the database is connectable. Because we might have
739 # just created it, keep trying for a few seconds incase PostgreSQL733 # just created it, keep trying for a few seconds incase PostgreSQL
740 # is taking its time getting its house in order.734 # is taking its time getting its house in order.
741 attempts = 60735 attempts = 60
742 for count in range(0, attempts):736 for count in range(0, attempts):
743 try:737 try:
744 DatabaseLayer.connect().close()738 cls.connect().close()
745 except psycopg2.Error:739 except psycopg2.Error:
746 if count == attempts - 1:740 if count == attempts - 1:
747 raise741 raise
@@ -749,24 +743,20 @@
749 else:743 else:
750 break744 break
751745
752 if DatabaseLayer.use_mockdb is True:746 if cls.use_mockdb is True:
753 DatabaseLayer.installMockDb()747 cls.installMockDb()
754748
755 @classmethod749 @classmethod
756 @profiled750 @profiled
757 def testTearDown(cls):751 def testTearDown(cls):
758 if DatabaseLayer.use_mockdb is True:752 if cls.use_mockdb is True:
759 DatabaseLayer.uninstallMockDb()753 cls.uninstallMockDb()
760754
761 # Ensure that the database is connectable755 # Ensure that the database is connectable
762 DatabaseLayer.connect().close()756 cls.connect().close()
763757
764 # Imported here to avoid circular import issues. This758 if cls._reset_between_tests:
765 # functionality should be migrated into this module at some759 cls._db_fixture.tearDown()
766 # point. -- StuartBishop 20060712
767 from canonical.launchpad.ftests.harness import LaunchpadTestSetup
768 if DatabaseLayer._reset_between_tests:
769 LaunchpadTestSetup().tearDown()
770760
771 # Fail tests that forget to uninstall their database policies.761 # Fail tests that forget to uninstall their database policies.
772 from canonical.launchpad.webapp.adapter import StoreSelector762 from canonical.launchpad.webapp.adapter import StoreSelector
@@ -781,7 +771,7 @@
781 @classmethod771 @classmethod
782 @profiled772 @profiled
783 def installMockDb(cls):773 def installMockDb(cls):
784 assert DatabaseLayer.mockdb_mode is None, 'mock db already installed'774 assert cls.mockdb_mode is None, 'mock db already installed'
785775
786 from canonical.testing.mockdb import (776 from canonical.testing.mockdb import (
787 script_filename, ScriptRecorder, ScriptPlayer,777 script_filename, ScriptRecorder, ScriptPlayer,
@@ -795,32 +785,32 @@
795 # mock db script.785 # mock db script.
796 filename = script_filename(test_key)786 filename = script_filename(test_key)
797 if os.path.exists(filename):787 if os.path.exists(filename):
798 DatabaseLayer.mockdb_mode = 'replay'788 cls.mockdb_mode = 'replay'
799 DatabaseLayer.script = ScriptPlayer(test_key)789 cls.script = ScriptPlayer(test_key)
800 else:790 else:
801 DatabaseLayer.mockdb_mode = 'record'791 cls.mockdb_mode = 'record'
802 DatabaseLayer.script = ScriptRecorder(test_key)792 cls.script = ScriptRecorder(test_key)
803793
804 global _org_connect794 global _org_connect
805 _org_connect = psycopg2.connect795 _org_connect = psycopg2.connect
806 # Proxy real connections with our mockdb.796 # Proxy real connections with our mockdb.
807 def fake_connect(*args, **kw):797 def fake_connect(*args, **kw):
808 return DatabaseLayer.script.connect(_org_connect, *args, **kw)798 return cls.script.connect(_org_connect, *args, **kw)
809 psycopg2.connect = fake_connect799 psycopg2.connect = fake_connect
810800
811 @classmethod801 @classmethod
812 @profiled802 @profiled
813 def uninstallMockDb(cls):803 def uninstallMockDb(cls):
814 if DatabaseLayer.mockdb_mode is None:804 if cls.mockdb_mode is None:
815 return # Already uninstalled805 return # Already uninstalled
816806
817 # Store results if we are recording807 # Store results if we are recording
818 if DatabaseLayer.mockdb_mode == 'record':808 if cls.mockdb_mode == 'record':
819 DatabaseLayer.script.store()809 cls.script.store()
820 assert os.path.exists(DatabaseLayer.script.script_filename), (810 assert os.path.exists(cls.script.script_filename), (
821 "Stored results but no script on disk.")811 "Stored results but no script on disk.")
822812
823 DatabaseLayer.mockdb_mode = None813 cls.mockdb_mode = None
824 global _org_connect814 global _org_connect
825 psycopg2.connect = _org_connect815 psycopg2.connect = _org_connect
826 _org_connect = None816 _org_connect = None
@@ -828,20 +818,17 @@
828 @classmethod818 @classmethod
829 @profiled819 @profiled
830 def force_dirty_database(cls):820 def force_dirty_database(cls):
831 from canonical.launchpad.ftests.harness import LaunchpadTestSetup821 cls._db_fixture.force_dirty_database()
832 LaunchpadTestSetup().force_dirty_database()
833822
834 @classmethod823 @classmethod
835 @profiled824 @profiled
836 def connect(cls):825 def connect(cls):
837 from canonical.launchpad.ftests.harness import LaunchpadTestSetup826 return cls._db_fixture.connect()
838 return LaunchpadTestSetup().connect()
839827
840 @classmethod828 @classmethod
841 @profiled829 @profiled
842 def _dropDb(cls):830 def _dropDb(cls):
843 from canonical.launchpad.ftests.harness import LaunchpadTestSetup831 return cls._db_fixture.dropDb()
844 return LaunchpadTestSetup().dropDb()
845832
846833
847def test_default_timeout():834def test_default_timeout():
@@ -1378,6 +1365,11 @@
1378 reconnect_stores(database_config_section=database_config_section)1365 reconnect_stores(database_config_section=database_config_section)
13791366
13801367
1368class LaunchpadTestSetup(PgTestSetup):
1369 template = 'launchpad_ftest_template'
1370 dbuser = 'launchpad'
1371
1372
1381class LaunchpadZopelessLayer(LaunchpadScriptLayer):1373class LaunchpadZopelessLayer(LaunchpadScriptLayer):
1382 """Full Zopeless environment including Component Architecture and1374 """Full Zopeless environment including Component Architecture and
1383 database connections initialized.1375 database connections initialized.
@@ -1643,6 +1635,9 @@
1643 # configs/testrunner-appserver/mail-configure.zcml1635 # configs/testrunner-appserver/mail-configure.zcml
1644 smtp_controller = None1636 smtp_controller = None
16451637
1638 # The DB fixture in use
1639 _db_fixture = None
1640
1646 @classmethod1641 @classmethod
1647 @profiled1642 @profiled
1648 def startSMTPServer(cls):1643 def startSMTPServer(cls):
@@ -1770,9 +1765,12 @@
1770 @classmethod1765 @classmethod
1771 def _runAppServer(cls):1766 def _runAppServer(cls):
1772 """Start the app server using runlaunchpad.py"""1767 """Start the app server using runlaunchpad.py"""
1773 from canonical.launchpad.ftests.harness import LaunchpadTestSetup
1774 # The database must be available for the app server to start.1768 # The database must be available for the app server to start.
1775 LaunchpadTestSetup().setUp()1769 cls._db_fixture = LaunchpadTestSetup()
1770 # This is not torn down properly: rather the singleton nature is abused
1771 # and the fixture is simply marked as being dirty.
1772 # XXX: Robert Collins 2010-10-17 bug=661967
1773 cls._db_fixture.setUp()
1776 # The app server will not start at all if the database hasn't been1774 # The app server will not start at all if the database hasn't been
1777 # correctly patched. The app server will make exactly this check,1775 # correctly patched. The app server will make exactly this check,
1778 # doing it here makes the error more obvious.1776 # doing it here makes the error more obvious.
17791777
=== modified file 'lib/lp/codehosting/tests/test_acceptance.py'
--- lib/lp/codehosting/tests/test_acceptance.py 2010-10-04 19:50:45 +0000
+++ lib/lp/codehosting/tests/test_acceptance.py 2010-10-17 19:12:52 +0000
@@ -21,7 +21,6 @@
21from zope.component import getUtility21from zope.component import getUtility
2222
23from canonical.config import config23from canonical.config import config
24from canonical.launchpad.ftests.harness import LaunchpadZopelessTestSetup
25from canonical.testing.layers import ZopelessAppServerLayer24from canonical.testing.layers import ZopelessAppServerLayer
26from canonical.testing.profiled import profiled25from canonical.testing.profiled import profiled
27from lp.code.bzr import (26from lp.code.bzr import (
@@ -334,7 +333,7 @@
334 remote_url = self.getTransportURL('~testuser/+junk/test-branch')333 remote_url = self.getTransportURL('~testuser/+junk/test-branch')
335 self.push(self.local_branch_path, remote_url)334 self.push(self.local_branch_path, remote_url)
336 self.assertBranchesMatch(self.local_branch_path, remote_url)335 self.assertBranchesMatch(self.local_branch_path, remote_url)
337 LaunchpadZopelessTestSetup().txn.begin()336 ZopelessAppServerLayer.txn.begin()
338 db_branch = getUtility(IBranchSet).getByUniqueName(337 db_branch = getUtility(IBranchSet).getByUniqueName(
339 '~testuser/+junk/test-branch')338 '~testuser/+junk/test-branch')
340 self.assertEqual(339 self.assertEqual(
@@ -343,7 +342,7 @@
343 BranchFormat.BZR_BRANCH_7, db_branch.branch_format)342 BranchFormat.BZR_BRANCH_7, db_branch.branch_format)
344 self.assertEqual(343 self.assertEqual(
345 ControlFormat.BZR_METADIR_1, db_branch.control_format)344 ControlFormat.BZR_METADIR_1, db_branch.control_format)
346 LaunchpadZopelessTestSetup().txn.commit()345 ZopelessAppServerLayer.txn.commit()
347346
348 def test_push_to_existing_branch(self):347 def test_push_to_existing_branch(self):
349 """Pushing to an existing branch must work."""348 """Pushing to an existing branch must work."""
@@ -374,12 +373,12 @@
374 self.push(self.local_branch_path, remote_url)373 self.push(self.local_branch_path, remote_url)
375374
376 # Rename owner, product and branch in the database375 # Rename owner, product and branch in the database
377 LaunchpadZopelessTestSetup().txn.begin()376 ZopelessAppServerLayer.txn.begin()
378 branch = self.getDatabaseBranch('testuser', None, 'test-branch')377 branch = self.getDatabaseBranch('testuser', None, 'test-branch')
379 branch.owner.name = 'renamed-user'378 branch.owner.name = 'renamed-user'
380 branch.setTarget(user=branch.owner, project=Product.byName('firefox'))379 branch.setTarget(user=branch.owner, project=Product.byName('firefox'))
381 branch.name = 'renamed-branch'380 branch.name = 'renamed-branch'
382 LaunchpadZopelessTestSetup().txn.commit()381 ZopelessAppServerLayer.txn.commit()
383382
384 # Check that it's not at the old location.383 # Check that it's not at the old location.
385 self.assertNotBranch(384 self.assertNotBranch(
@@ -405,23 +404,23 @@
405 '~testuser/+junk/totally-new-branch')404 '~testuser/+junk/totally-new-branch')
406 self.push(self.local_branch_path, remote_url)405 self.push(self.local_branch_path, remote_url)
407406
408 LaunchpadZopelessTestSetup().txn.begin()407 ZopelessAppServerLayer.txn.begin()
409 branch = self.getDatabaseBranch(408 branch = self.getDatabaseBranch(
410 'testuser', None, 'totally-new-branch')409 'testuser', None, 'totally-new-branch')
411410
412 self.assertEqual(411 self.assertEqual(
413 ['~testuser/+junk/totally-new-branch', self.revid],412 ['~testuser/+junk/totally-new-branch', self.revid],
414 [branch.unique_name, branch.last_mirrored_id])413 [branch.unique_name, branch.last_mirrored_id])
415 LaunchpadZopelessTestSetup().txn.abort()414 ZopelessAppServerLayer.txn.abort()
416415
417 def test_record_default_stacking(self):416 def test_record_default_stacking(self):
418 # If the location being pushed to has a default stacked-on branch,417 # If the location being pushed to has a default stacked-on branch,
419 # then branches pushed to that location end up stacked on it by418 # then branches pushed to that location end up stacked on it by
420 # default.419 # default.
421 product = self.factory.makeProduct()420 product = self.factory.makeProduct()
422 LaunchpadZopelessTestSetup().txn.commit()421 ZopelessAppServerLayer.txn.commit()
423422
424 LaunchpadZopelessTestSetup().txn.begin()423 ZopelessAppServerLayer.txn.begin()
425424
426 self.make_branch_and_tree('stacked-on')425 self.make_branch_and_tree('stacked-on')
427 trunk_unique_name = '~testuser/%s/trunk' % product.name426 trunk_unique_name = '~testuser/%s/trunk' % product.name
@@ -431,7 +430,7 @@
431 self.factory.enableDefaultStackingForProduct(430 self.factory.enableDefaultStackingForProduct(
432 db_trunk.product, db_trunk)431 db_trunk.product, db_trunk)
433432
434 LaunchpadZopelessTestSetup().txn.commit()433 ZopelessAppServerLayer.txn.commit()
435434
436 stacked_unique_name = '~testuser/%s/stacked' % product.name435 stacked_unique_name = '~testuser/%s/stacked' % product.name
437 self.push(436 self.push(
@@ -447,7 +446,7 @@
447 # attribute of the database branch, and stacked on location of the new446 # attribute of the database branch, and stacked on location of the new
448 # branch is normalized to be a relative path.447 # branch is normalized to be a relative path.
449 product = self.factory.makeProduct()448 product = self.factory.makeProduct()
450 LaunchpadZopelessTestSetup().txn.commit()449 ZopelessAppServerLayer.txn.commit()
451450
452 self.make_branch_and_tree('stacked-on')451 self.make_branch_and_tree('stacked-on')
453 trunk_unique_name = '~testuser/%s/trunk' % product.name452 trunk_unique_name = '~testuser/%s/trunk' % product.name
@@ -507,11 +506,11 @@
507 def test_push_to_new_short_branch_alias(self):506 def test_push_to_new_short_branch_alias(self):
508 # We can also push branches to URLs like /+branch/firefox507 # We can also push branches to URLs like /+branch/firefox
509 # Hack 'firefox' so we have permission to do this.508 # Hack 'firefox' so we have permission to do this.
510 LaunchpadZopelessTestSetup().txn.begin()509 ZopelessAppServerLayer.txn.begin()
511 firefox = Product.selectOneBy(name='firefox')510 firefox = Product.selectOneBy(name='firefox')
512 testuser = Person.selectOneBy(name='testuser')511 testuser = Person.selectOneBy(name='testuser')
513 firefox.development_focus.owner = testuser512 firefox.development_focus.owner = testuser
514 LaunchpadZopelessTestSetup().txn.commit()513 ZopelessAppServerLayer.txn.commit()
515 remote_url = self.getTransportURL('+branch/firefox')514 remote_url = self.getTransportURL('+branch/firefox')
516 self.push(self.local_branch_path, remote_url)515 self.push(self.local_branch_path, remote_url)
517 self.assertBranchesMatch(self.local_branch_path, remote_url)516 self.assertBranchesMatch(self.local_branch_path, remote_url)
@@ -520,10 +519,10 @@
520 # If a hosted branch exists in the database, but not on the519 # If a hosted branch exists in the database, but not on the
521 # filesystem, and is writable by the user, then the user is able to520 # filesystem, and is writable by the user, then the user is able to
522 # push to it.521 # push to it.
523 LaunchpadZopelessTestSetup().txn.begin()522 ZopelessAppServerLayer.txn.begin()
524 branch = self.makeDatabaseBranch('testuser', 'firefox', 'some-branch')523 branch = self.makeDatabaseBranch('testuser', 'firefox', 'some-branch')
525 remote_url = self.getTransportURL(branch.unique_name)524 remote_url = self.getTransportURL(branch.unique_name)
526 LaunchpadZopelessTestSetup().txn.commit()525 ZopelessAppServerLayer.txn.commit()
527 self.push(526 self.push(
528 self.local_branch_path, remote_url,527 self.local_branch_path, remote_url,
529 extra_args=['--use-existing-dir'])528 extra_args=['--use-existing-dir'])
@@ -531,21 +530,21 @@
531530
532 def test_cant_push_to_existing_mirrored_branch(self):531 def test_cant_push_to_existing_mirrored_branch(self):
533 # Users cannot push to mirrored branches.532 # Users cannot push to mirrored branches.
534 LaunchpadZopelessTestSetup().txn.begin()533 ZopelessAppServerLayer.txn.begin()
535 branch = self.makeDatabaseBranch(534 branch = self.makeDatabaseBranch(
536 'testuser', 'firefox', 'some-branch', BranchType.MIRRORED)535 'testuser', 'firefox', 'some-branch', BranchType.MIRRORED)
537 remote_url = self.getTransportURL(branch.unique_name)536 remote_url = self.getTransportURL(branch.unique_name)
538 LaunchpadZopelessTestSetup().txn.commit()537 ZopelessAppServerLayer.txn.commit()
539 self.assertCantPush(538 self.assertCantPush(
540 self.local_branch_path, remote_url,539 self.local_branch_path, remote_url,
541 ['Permission denied:', 'Transport operation not possible:'])540 ['Permission denied:', 'Transport operation not possible:'])
542541
543 def test_cant_push_to_existing_unowned_hosted_branch(self):542 def test_cant_push_to_existing_unowned_hosted_branch(self):
544 # Users can only push to hosted branches that they own.543 # Users can only push to hosted branches that they own.
545 LaunchpadZopelessTestSetup().txn.begin()544 ZopelessAppServerLayer.txn.begin()
546 branch = self.makeDatabaseBranch('mark', 'firefox', 'some-branch')545 branch = self.makeDatabaseBranch('mark', 'firefox', 'some-branch')
547 remote_url = self.getTransportURL(branch.unique_name)546 remote_url = self.getTransportURL(branch.unique_name)
548 LaunchpadZopelessTestSetup().txn.commit()547 ZopelessAppServerLayer.txn.commit()
549 self.assertCantPush(548 self.assertCantPush(
550 self.local_branch_path, remote_url,549 self.local_branch_path, remote_url,
551 ['Permission denied:', 'Transport operation not possible:'])550 ['Permission denied:', 'Transport operation not possible:'])
@@ -566,12 +565,12 @@
566 person_name, product_name, branch_name)565 person_name, product_name, branch_name)
567566
568 # Mark as mirrored.567 # Mark as mirrored.
569 LaunchpadZopelessTestSetup().txn.begin()568 ZopelessAppServerLayer.txn.begin()
570 branch = self.getDatabaseBranch(569 branch = self.getDatabaseBranch(
571 person_name, product_name, branch_name)570 person_name, product_name, branch_name)
572 branch.branch_type = BranchType.MIRRORED571 branch.branch_type = BranchType.MIRRORED
573 branch.url = "http://example.com/smartservertest/branch"572 branch.url = "http://example.com/smartservertest/branch"
574 LaunchpadZopelessTestSetup().txn.commit()573 ZopelessAppServerLayer.txn.commit()
575 return ro_branch_url574 return ro_branch_url
576575
577 def test_can_read_readonly_branch(self):576 def test_can_read_readonly_branch(self):
578577
=== modified file 'lib/lp/soyuz/doc/sampledata-setup.txt'
--- lib/lp/soyuz/doc/sampledata-setup.txt 2010-08-13 02:59:14 +0000
+++ lib/lp/soyuz/doc/sampledata-setup.txt 2010-10-17 19:12:52 +0000
@@ -21,5 +21,5 @@
21 INFO ...21 INFO ...
22 INFO Done.22 INFO Done.
2323
24 >>> from canonical.launchpad.ftests.harness import LaunchpadTestSetup24 >>> from canonical.testing.layers import DatabaseLayer
25 >>> LaunchpadTestSetup().force_dirty_database()25 >>> DatabaseLayer.force_dirty_database()
2626
=== modified file 'lib/lp/soyuz/scripts/tests/test_buildd_cronscripts.py'
--- lib/lp/soyuz/scripts/tests/test_buildd_cronscripts.py 2010-10-04 19:50:45 +0000
+++ lib/lp/soyuz/scripts/tests/test_buildd_cronscripts.py 2010-10-17 19:12:52 +0000
@@ -74,9 +74,8 @@
74 rc, out, err = runner()74 rc, out, err = runner()
75 self.assertEqual(0, rc, "Err:\n%s" % err)75 self.assertEqual(0, rc, "Err:\n%s" % err)
7676
77 # 'runners' commit to the launchpad_ftest database in77 # 'runners' commit to the test database in subprocesses, so we need to
78 # subprocesses, so we need to tell the layer to fully78 # tell the layer to fully tear down and restore the database.
79 # tear down and restore the database.
80 DatabaseLayer.force_dirty_database()79 DatabaseLayer.force_dirty_database()
8180
82 return rc, out, err81 return rc, out, err
8382
=== modified file 'lib/lp/translations/doc/fix_translation_credits.txt'
--- lib/lp/translations/doc/fix_translation_credits.txt 2010-04-01 04:05:10 +0000
+++ lib/lp/translations/doc/fix_translation_credits.txt 2010-10-17 19:12:52 +0000
@@ -19,5 +19,5 @@
19After altering the database from a separate process, we must tell the19After altering the database from a separate process, we must tell the
20test setup that the database is dirty in spite of appearances.20test setup that the database is dirty in spite of appearances.
2121
22 >>> from canonical.launchpad.ftests.harness import LaunchpadTestSetup22 >>> from canonical.testing.layers import DatabaseLayer
23 >>> LaunchpadTestSetup().force_dirty_database()23 >>> DatabaseLayer.force_dirty_database()
2424
=== modified file 'lib/lp/translations/doc/message-sharing-merge-script.txt'
--- lib/lp/translations/doc/message-sharing-merge-script.txt 2009-08-04 13:37:57 +0000
+++ lib/lp/translations/doc/message-sharing-merge-script.txt 2010-10-17 19:12:52 +0000
@@ -20,5 +20,5 @@
20# The script modified the database, even though the database layer may20# The script modified the database, even though the database layer may
21# not have noticed it.21# not have noticed it.
2222
23 >>> from canonical.launchpad.ftests.harness import LaunchpadTestSetup23 >>> from canonical.testing.layers import DatabaseLayer
24 >>> LaunchpadTestSetup().force_dirty_database()24 >>> DatabaseLayer.force_dirty_database()
2525
=== modified file 'lib/lp/translations/doc/request_country.txt'
--- lib/lp/translations/doc/request_country.txt 2010-02-26 21:58:15 +0000
+++ lib/lp/translations/doc/request_country.txt 2010-10-17 19:12:52 +0000
@@ -4,10 +4,6 @@
44
5Adapting a request to a country allows you to see where the request came from.5Adapting a request to a country allows you to see where the request came from.
66
7 >>> from canonical.launchpad.ftests.harness import (
8 ... LaunchpadFunctionalTestSetup)
9 >>> LaunchpadFunctionalTestSetup().setUp()
10
11Here's a dummy request. Zope adds the REMOTE_ADDR CGI environment variable7Here's a dummy request. Zope adds the REMOTE_ADDR CGI environment variable
12for us. Upstream proxy servers (and tinkering users!) may also add8for us. Upstream proxy servers (and tinkering users!) may also add
13X-Forwarded-For: headers. The X-Forwarded-For: header takes precidence9X-Forwarded-For: headers. The X-Forwarded-For: header takes precidence
@@ -34,6 +30,3 @@
34 Traceback (most recent call last):30 Traceback (most recent call last):
35 ...31 ...
36 TypeError: ('Could not adapt', ...32 TypeError: ('Could not adapt', ...
37
38 >>> LaunchpadFunctionalTestSetup().tearDown()
39