Merge lp:~lifeless/launchpad/databasefixture into lp:launchpad
- databasefixture
- Merge into devel
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 |
Related bugs: |
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 : | # |
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
1 | === modified file 'lib/canonical/config/tests/test_database_config.py' | |||
2 | --- lib/canonical/config/tests/test_database_config.py 2010-01-13 20:06:09 +0000 | |||
3 | +++ lib/canonical/config/tests/test_database_config.py 2010-10-17 19:12:52 +0000 | |||
4 | @@ -3,17 +3,20 @@ | |||
5 | 3 | 3 | ||
6 | 4 | __metaclass__ = type | 4 | __metaclass__ = type |
7 | 5 | 5 | ||
8 | 6 | from lp.testing import TestCase | ||
9 | 7 | |||
10 | 8 | from canonical.config import config, dbconfig | 6 | from canonical.config import config, dbconfig |
11 | 9 | |||
12 | 10 | from canonical.launchpad.readonly import read_only_file_exists | 7 | from canonical.launchpad.readonly import read_only_file_exists |
13 | 11 | from canonical.launchpad.tests.readonly import ( | 8 | from canonical.launchpad.tests.readonly import ( |
15 | 12 | remove_read_only_file, touch_read_only_file) | 9 | remove_read_only_file, |
16 | 10 | touch_read_only_file, | ||
17 | 11 | ) | ||
18 | 12 | from canonical.testing.layers import DatabaseLayer | ||
19 | 13 | from lp.testing import TestCase | ||
20 | 13 | 14 | ||
21 | 14 | 15 | ||
22 | 15 | class TestDatabaseConfig(TestCase): | 16 | class TestDatabaseConfig(TestCase): |
23 | 16 | 17 | ||
24 | 18 | layer = DatabaseLayer | ||
25 | 19 | |||
26 | 17 | def test_overlay(self): | 20 | def test_overlay(self): |
27 | 18 | # The dbconfig option overlays the database configurations of a | 21 | # The dbconfig option overlays the database configurations of a |
28 | 19 | # chosen config section over the base section. | 22 | # chosen config section over the base section. |
29 | @@ -25,11 +28,12 @@ | |||
30 | 25 | self.assertEquals('librarian', config.librarian.dbuser) | 28 | self.assertEquals('librarian', config.librarian.dbuser) |
31 | 26 | 29 | ||
32 | 27 | dbconfig.setConfigSection('librarian') | 30 | dbconfig.setConfigSection('librarian') |
34 | 28 | self.assertEquals('dbname=launchpad_ftest', dbconfig.rw_main_master) | 31 | expected_db = 'dbname=%s' % DatabaseLayer._db_fixture.dbname |
35 | 32 | self.assertEquals(expected_db, dbconfig.rw_main_master) | ||
36 | 29 | self.assertEquals('librarian', dbconfig.dbuser) | 33 | self.assertEquals('librarian', dbconfig.dbuser) |
37 | 30 | 34 | ||
38 | 31 | dbconfig.setConfigSection('launchpad') | 35 | dbconfig.setConfigSection('launchpad') |
40 | 32 | self.assertEquals('dbname=launchpad_ftest', dbconfig.rw_main_master) | 36 | self.assertEquals(expected_db, dbconfig.rw_main_master) |
41 | 33 | self.assertEquals('launchpad_main', dbconfig.dbuser) | 37 | self.assertEquals('launchpad_main', dbconfig.dbuser) |
42 | 34 | 38 | ||
43 | 35 | def test_required_values(self): | 39 | def test_required_values(self): |
44 | 36 | 40 | ||
45 | === modified file 'lib/canonical/database/ftests/test_postgresql.py' | |||
46 | --- lib/canonical/database/ftests/test_postgresql.py 2010-07-14 14:11:15 +0000 | |||
47 | +++ lib/canonical/database/ftests/test_postgresql.py 2010-10-17 19:12:52 +0000 | |||
48 | @@ -10,8 +10,9 @@ | |||
49 | 10 | def setUp(test): | 10 | def setUp(test): |
50 | 11 | 11 | ||
51 | 12 | # Build a fresh, empty database and connect | 12 | # Build a fresh, empty database and connect |
54 | 13 | PgTestSetup().setUp() | 13 | test._db_fixture = PgTestSetup() |
55 | 14 | con = PgTestSetup().connect() | 14 | test._db_fixture.setUp() |
56 | 15 | con = test._db_fixture.connect() | ||
57 | 15 | 16 | ||
58 | 16 | # Create a test schema demonstrating the edge cases | 17 | # Create a test schema demonstrating the edge cases |
59 | 17 | cur = con.cursor() | 18 | cur = con.cursor() |
60 | @@ -53,8 +54,9 @@ | |||
61 | 53 | test.globs['cur'] = cur | 54 | test.globs['cur'] = cur |
62 | 54 | 55 | ||
63 | 55 | def tearDown(test): | 56 | def tearDown(test): |
64 | 56 | PgTestSetup().tearDown() | ||
65 | 57 | test.globs['con'].close() | 57 | test.globs['con'].close() |
66 | 58 | test._db_fixture.tearDown() | ||
67 | 59 | del test._db_fixture | ||
68 | 58 | 60 | ||
69 | 59 | def test_suite(): | 61 | def test_suite(): |
70 | 60 | suite = DocTestSuite( | 62 | suite = DocTestSuite( |
71 | 61 | 63 | ||
72 | === modified file 'lib/canonical/database/ftests/test_sqlbaseconnect.txt' | |||
73 | --- lib/canonical/database/ftests/test_sqlbaseconnect.txt 2009-04-17 10:32:16 +0000 | |||
74 | +++ lib/canonical/database/ftests/test_sqlbaseconnect.txt 2010-10-17 19:12:52 +0000 | |||
75 | @@ -19,7 +19,7 @@ | |||
76 | 19 | Specifying the user connects as that user. | 19 | Specifying the user connects as that user. |
77 | 20 | 20 | ||
78 | 21 | >>> do_connect(user=config.launchpad_session.dbuser) | 21 | >>> do_connect(user=config.launchpad_session.dbuser) |
80 | 22 | Connected as session to launchpad_ftest in read committed isolation. | 22 | Connected as session to ... in read committed isolation. |
81 | 23 | 23 | ||
82 | 24 | Specifying the database name connects to that database. | 24 | Specifying the database name connects to that database. |
83 | 25 | 25 | ||
84 | @@ -31,5 +31,5 @@ | |||
85 | 31 | >>> do_connect( | 31 | >>> do_connect( |
86 | 32 | ... user=config.launchpad.dbuser, | 32 | ... user=config.launchpad.dbuser, |
87 | 33 | ... isolation=ISOLATION_LEVEL_SERIALIZABLE) | 33 | ... isolation=ISOLATION_LEVEL_SERIALIZABLE) |
89 | 34 | Connected as launchpad_main to launchpad_ftest in serializable isolation. | 34 | Connected as launchpad_main to ... in serializable isolation. |
90 | 35 | 35 | ||
91 | 36 | 36 | ||
92 | === modified file 'lib/canonical/ftests/pgsql.py' | |||
93 | --- lib/canonical/ftests/pgsql.py 2009-10-09 04:05:34 +0000 | |||
94 | +++ lib/canonical/ftests/pgsql.py 2010-10-17 19:12:52 +0000 | |||
95 | @@ -7,7 +7,7 @@ | |||
96 | 7 | 7 | ||
97 | 8 | __metaclass__ = type | 8 | __metaclass__ = type |
98 | 9 | 9 | ||
100 | 10 | import unittest | 10 | import os |
101 | 11 | import time | 11 | import time |
102 | 12 | 12 | ||
103 | 13 | import psycopg2 | 13 | import psycopg2 |
104 | @@ -119,7 +119,6 @@ | |||
105 | 119 | 119 | ||
106 | 120 | _org_connect = None | 120 | _org_connect = None |
107 | 121 | def fake_connect(*args, **kw): | 121 | def fake_connect(*args, **kw): |
108 | 122 | global _org_connect | ||
109 | 123 | return ConnectionWrapper(_org_connect(*args, **kw)) | 122 | return ConnectionWrapper(_org_connect(*args, **kw)) |
110 | 124 | 123 | ||
111 | 125 | def installFakeConnect(): | 124 | def installFakeConnect(): |
112 | @@ -136,9 +135,13 @@ | |||
113 | 136 | 135 | ||
114 | 137 | 136 | ||
115 | 138 | class PgTestSetup: | 137 | class PgTestSetup: |
116 | 138 | |||
117 | 139 | connections = [] # Shared | 139 | connections = [] # Shared |
118 | 140 | # Use a dynamically generated dbname: | ||
119 | 141 | dynamic = object() | ||
120 | 140 | 142 | ||
121 | 141 | template = 'template1' | 143 | template = 'template1' |
122 | 144 | # Needs to match configs/testrunner*/*: | ||
123 | 142 | dbname = 'launchpad_ftest' | 145 | dbname = 'launchpad_ftest' |
124 | 143 | dbuser = None | 146 | dbuser = None |
125 | 144 | host = None | 147 | host = None |
126 | @@ -165,8 +168,13 @@ | |||
127 | 165 | ''' | 168 | ''' |
128 | 166 | if template is not None: | 169 | if template is not None: |
129 | 167 | self.template = template | 170 | self.template = template |
131 | 168 | if dbname is not None: | 171 | if dbname is PgTestSetup.dynamic: |
132 | 172 | self.dbname = self.__class__.dbname + "_" + str(os.getpid()) | ||
133 | 173 | elif dbname is not None: | ||
134 | 169 | self.dbname = dbname | 174 | self.dbname = dbname |
135 | 175 | else: | ||
136 | 176 | # Fallback to the class name. | ||
137 | 177 | self.dbname = self.__class__.dbname | ||
138 | 170 | if dbuser is not None: | 178 | if dbuser is not None: |
139 | 171 | self.dbuser = dbuser | 179 | self.dbuser = dbuser |
140 | 172 | if host is not None: | 180 | if host is not None: |
141 | @@ -331,30 +339,3 @@ | |||
142 | 331 | as database changes made from a subprocess. | 339 | as database changes made from a subprocess. |
143 | 332 | """ | 340 | """ |
144 | 333 | PgTestSetup._reset_db = True | 341 | PgTestSetup._reset_db = True |
145 | 334 | |||
146 | 335 | |||
147 | 336 | class PgTestCase(unittest.TestCase): | ||
148 | 337 | dbname = None | ||
149 | 338 | dbuser = None | ||
150 | 339 | host = None | ||
151 | 340 | port = None | ||
152 | 341 | template = None | ||
153 | 342 | def setUp(self): | ||
154 | 343 | pg_test_setup = PgTestSetup( | ||
155 | 344 | self.template, self.dbname, self.dbuser, self.host, self.port | ||
156 | 345 | ) | ||
157 | 346 | pg_test_setup.setUp() | ||
158 | 347 | self.dbname = pg_test_setup.dbname | ||
159 | 348 | self.dbuser = pg_test_setup.dbuser | ||
160 | 349 | assert self.dbname, 'self.dbname is not set.' | ||
161 | 350 | |||
162 | 351 | def tearDown(self): | ||
163 | 352 | PgTestSetup( | ||
164 | 353 | self.template, self.dbname, self.dbuser, self.host, self.port | ||
165 | 354 | ).tearDown() | ||
166 | 355 | |||
167 | 356 | def connect(self): | ||
168 | 357 | return PgTestSetup( | ||
169 | 358 | self.template, self.dbname, self.dbuser, self.host, self.port | ||
170 | 359 | ).connect() | ||
171 | 360 | |||
172 | 361 | 342 | ||
173 | === modified file 'lib/canonical/ftests/test_pgsql.py' | |||
174 | --- lib/canonical/ftests/test_pgsql.py 2009-06-25 05:30:52 +0000 | |||
175 | +++ lib/canonical/ftests/test_pgsql.py 2010-10-17 19:12:52 +0000 | |||
176 | @@ -1,77 +1,84 @@ | |||
178 | 1 | # Copyright 2009 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2010 Canonical Ltd. This software is licensed under the |
179 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
180 | 3 | 3 | ||
203 | 4 | import unittest | 4 | import os |
204 | 5 | from canonical.ftests.pgsql import PgTestCase, PgTestSetup, ConnectionWrapper | 5 | |
205 | 6 | 6 | import testtools | |
206 | 7 | 7 | ||
207 | 8 | class TestPgTestCase(PgTestCase): | 8 | from canonical.ftests.pgsql import ( |
208 | 9 | 9 | ConnectionWrapper, | |
209 | 10 | def testRollback(self): | 10 | PgTestSetup, |
210 | 11 | # This test creates a table. We run the same test twice, | 11 | ) |
211 | 12 | # which will fail if database changes are not rolled back | 12 | |
212 | 13 | con = self.connect() | 13 | |
213 | 14 | cur = con.cursor() | 14 | class TestPgTestSetup(testtools.TestCase): |
214 | 15 | cur.execute('CREATE TABLE foo (x int)') | 15 | |
215 | 16 | cur.execute('INSERT INTO foo VALUES (1)') | 16 | def test_db_naming(self): |
216 | 17 | cur.execute('SELECT x FROM foo') | 17 | fixture = PgTestSetup(dbname=PgTestSetup.dynamic) |
217 | 18 | res = list(cur.fetchall()) | 18 | expected_name = "%s_%s" % (PgTestSetup.dbname, os.getpid()) |
218 | 19 | self.failUnless(len(res) == 1) | 19 | self.assertEqual(expected_name, fixture.dbname) |
219 | 20 | self.failUnless(res[0][0] == 1) | 20 | fixture.setUp() |
220 | 21 | con.commit() | 21 | self.addCleanup(fixture.dropDb) |
221 | 22 | 22 | self.addCleanup(fixture.tearDown) | |
222 | 23 | testRollback2 = testRollback | 23 | cur = fixture.connect().cursor() |
223 | 24 | 24 | cur.execute('SELECT current_database()') | |
224 | 25 | class TestOptimization(unittest.TestCase): | 25 | where = cur.fetchone()[0] |
225 | 26 | self.assertEqual(expected_name, where) | ||
226 | 27 | |||
227 | 26 | def testOptimization(self): | 28 | def testOptimization(self): |
228 | 27 | # Test to ensure that the database is destroyed only when necessary | 29 | # Test to ensure that the database is destroyed only when necessary |
229 | 28 | 30 | ||
230 | 29 | # Make a change to a database | 31 | # Make a change to a database |
232 | 30 | PgTestSetup().setUp() | 32 | fixture = PgTestSetup() |
233 | 33 | fixture.setUp() | ||
234 | 31 | try: | 34 | try: |
236 | 32 | con = PgTestSetup().connect() | 35 | con = fixture.connect() |
237 | 33 | cur = con.cursor() | 36 | cur = con.cursor() |
238 | 34 | cur.execute('CREATE TABLE foo (x int)') | 37 | cur.execute('CREATE TABLE foo (x int)') |
239 | 35 | con.commit() | 38 | con.commit() |
240 | 36 | # Fake it so the harness doesn't know a change has been made | 39 | # Fake it so the harness doesn't know a change has been made |
241 | 37 | ConnectionWrapper.committed = False | 40 | ConnectionWrapper.committed = False |
242 | 38 | finally: | 41 | finally: |
244 | 39 | PgTestSetup().tearDown() | 42 | fixture.tearDown() |
245 | 40 | 43 | ||
248 | 41 | # Now check to ensure that the table we just created is still there | 44 | # Now check to ensure that the table we just created is still there if |
249 | 42 | PgTestSetup().setUp() | 45 | # we reuse the fixture. |
250 | 46 | fixture.setUp() | ||
251 | 43 | try: | 47 | try: |
253 | 44 | con = PgTestSetup().connect() | 48 | con = fixture.connect() |
254 | 45 | cur = con.cursor() | 49 | cur = con.cursor() |
255 | 46 | # This tests that the table still exists, as well as modifying the | 50 | # This tests that the table still exists, as well as modifying the |
256 | 47 | # db | 51 | # db |
257 | 48 | cur.execute('INSERT INTO foo VALUES (1)') | 52 | cur.execute('INSERT INTO foo VALUES (1)') |
258 | 49 | con.commit() | 53 | con.commit() |
259 | 50 | finally: | 54 | finally: |
261 | 51 | PgTestSetup().tearDown() | 55 | fixture.tearDown() |
262 | 52 | 56 | ||
265 | 53 | # Now ensure that the table is gone | 57 | # Now ensure that the table is gone - the commit must have been rolled |
266 | 54 | PgTestSetup().setUp() | 58 | # back. |
267 | 59 | fixture.setUp() | ||
268 | 55 | try: | 60 | try: |
270 | 56 | con = PgTestSetup().connect() | 61 | con = fixture.connect() |
271 | 57 | cur = con.cursor() | 62 | cur = con.cursor() |
272 | 58 | cur.execute('CREATE TABLE foo (x int)') | 63 | cur.execute('CREATE TABLE foo (x int)') |
273 | 59 | con.commit() | 64 | con.commit() |
274 | 60 | ConnectionWrapper.committed = False # Leave the table | 65 | ConnectionWrapper.committed = False # Leave the table |
275 | 61 | finally: | 66 | finally: |
277 | 62 | PgTestSetup().tearDown() | 67 | fixture.tearDown() |
278 | 63 | 68 | ||
283 | 64 | # The database should *always* be recreated if the template | 69 | # The database should *always* be recreated if a new template had been |
284 | 65 | # changes. | 70 | # chosen. |
285 | 66 | PgTestSetup._last_db = ('whatever', 'launchpad_ftest') | 71 | PgTestSetup._last_db = ('different-template', fixture.dbname) |
286 | 67 | PgTestSetup().setUp() | 72 | fixture.setUp() |
287 | 68 | try: | 73 | try: |
289 | 69 | con = PgTestSetup().connect() | 74 | con = fixture.connect() |
290 | 70 | cur = con.cursor() | 75 | cur = con.cursor() |
291 | 76 | # If this fails, TABLE foo still existed and the DB wasn't rebuilt | ||
292 | 77 | # correctly. | ||
293 | 71 | cur.execute('CREATE TABLE foo (x int)') | 78 | cur.execute('CREATE TABLE foo (x int)') |
294 | 72 | con.commit() | 79 | con.commit() |
295 | 73 | finally: | 80 | finally: |
297 | 74 | PgTestSetup().tearDown() | 81 | fixture.tearDown() |
298 | 75 | 82 | ||
299 | 76 | def test_sequences(self): | 83 | def test_sequences(self): |
300 | 77 | # Sequences may be affected by connections even if the connection | 84 | # Sequences may be affected by connections even if the connection |
301 | @@ -80,9 +87,10 @@ | |||
302 | 80 | # the sequences. | 87 | # the sequences. |
303 | 81 | 88 | ||
304 | 82 | # Setup a table that uses a sequence | 89 | # Setup a table that uses a sequence |
306 | 83 | PgTestSetup().setUp() | 90 | fixture = PgTestSetup() |
307 | 91 | fixture.setUp() | ||
308 | 84 | try: | 92 | try: |
310 | 85 | con = PgTestSetup().connect() | 93 | con = fixture.connect() |
311 | 86 | cur = con.cursor() | 94 | cur = con.cursor() |
312 | 87 | cur.execute('CREATE TABLE foo (x serial, y integer)') | 95 | cur.execute('CREATE TABLE foo (x serial, y integer)') |
313 | 88 | con.commit() | 96 | con.commit() |
314 | @@ -90,15 +98,15 @@ | |||
315 | 90 | # Fake it so the harness doesn't know a change has been made | 98 | # Fake it so the harness doesn't know a change has been made |
316 | 91 | ConnectionWrapper.committed = False | 99 | ConnectionWrapper.committed = False |
317 | 92 | finally: | 100 | finally: |
319 | 93 | PgTestSetup().tearDown() | 101 | fixture.tearDown() |
320 | 94 | 102 | ||
321 | 95 | sequence_values = [] | 103 | sequence_values = [] |
322 | 96 | # Insert a row into it and roll back the changes. Each time, we | 104 | # Insert a row into it and roll back the changes. Each time, we |
323 | 97 | # should end up with the same sequence value | 105 | # should end up with the same sequence value |
324 | 98 | for i in range(3): | 106 | for i in range(3): |
326 | 99 | PgTestSetup().setUp() | 107 | fixture.setUp() |
327 | 100 | try: | 108 | try: |
329 | 101 | con = PgTestSetup().connect() | 109 | con = fixture.connect() |
330 | 102 | cur = con.cursor() | 110 | cur = con.cursor() |
331 | 103 | cur.execute('INSERT INTO foo (y) VALUES (1)') | 111 | cur.execute('INSERT INTO foo (y) VALUES (1)') |
332 | 104 | cur.execute("SELECT currval('foo_x_seq')") | 112 | cur.execute("SELECT currval('foo_x_seq')") |
333 | @@ -106,7 +114,7 @@ | |||
334 | 106 | con.rollback() | 114 | con.rollback() |
335 | 107 | con.close() | 115 | con.close() |
336 | 108 | finally: | 116 | finally: |
338 | 109 | PgTestSetup().tearDown() | 117 | fixture.tearDown() |
339 | 110 | 118 | ||
340 | 111 | # Fail if we got a diffent sequence value at some point | 119 | # Fail if we got a diffent sequence value at some point |
341 | 112 | for v in sequence_values: | 120 | for v in sequence_values: |
342 | @@ -114,9 +122,9 @@ | |||
343 | 114 | 122 | ||
344 | 115 | # Repeat the test, but this time with some data already in the | 123 | # Repeat the test, but this time with some data already in the |
345 | 116 | # table | 124 | # table |
347 | 117 | PgTestSetup().setUp() | 125 | fixture.setUp() |
348 | 118 | try: | 126 | try: |
350 | 119 | con = PgTestSetup().connect() | 127 | con = fixture.connect() |
351 | 120 | cur = con.cursor() | 128 | cur = con.cursor() |
352 | 121 | cur.execute('INSERT INTO foo (y) VALUES (1)') | 129 | cur.execute('INSERT INTO foo (y) VALUES (1)') |
353 | 122 | con.commit() | 130 | con.commit() |
354 | @@ -124,15 +132,15 @@ | |||
355 | 124 | # Fake it so the harness doesn't know a change has been made | 132 | # Fake it so the harness doesn't know a change has been made |
356 | 125 | ConnectionWrapper.committed = False | 133 | ConnectionWrapper.committed = False |
357 | 126 | finally: | 134 | finally: |
359 | 127 | PgTestSetup().tearDown() | 135 | fixture.tearDown() |
360 | 128 | 136 | ||
361 | 129 | sequence_values = [] | 137 | sequence_values = [] |
362 | 130 | # Insert a row into it and roll back the changes. Each time, we | 138 | # Insert a row into it and roll back the changes. Each time, we |
363 | 131 | # should end up with the same sequence value | 139 | # should end up with the same sequence value |
364 | 132 | for i in range(1,3): | 140 | for i in range(1,3): |
366 | 133 | PgTestSetup().setUp() | 141 | fixture.setUp() |
367 | 134 | try: | 142 | try: |
369 | 135 | con = PgTestSetup().connect() | 143 | con = fixture.connect() |
370 | 136 | cur = con.cursor() | 144 | cur = con.cursor() |
371 | 137 | cur.execute('INSERT INTO foo (y) VALUES (1)') | 145 | cur.execute('INSERT INTO foo (y) VALUES (1)') |
372 | 138 | cur.execute("SELECT currval('foo_x_seq')") | 146 | cur.execute("SELECT currval('foo_x_seq')") |
373 | @@ -140,19 +148,8 @@ | |||
374 | 140 | con.rollback() | 148 | con.rollback() |
375 | 141 | con.close() | 149 | con.close() |
376 | 142 | finally: | 150 | finally: |
378 | 143 | PgTestSetup().tearDown() | 151 | fixture.tearDown() |
379 | 144 | 152 | ||
380 | 145 | # Fail if we got a diffent sequence value at some point | 153 | # Fail if we got a diffent sequence value at some point |
381 | 146 | for v in sequence_values: | 154 | for v in sequence_values: |
382 | 147 | self.failUnlessEqual(v, sequence_values[0]) | 155 | self.failUnlessEqual(v, sequence_values[0]) |
383 | 148 | |||
384 | 149 | |||
385 | 150 | def test_suite(): | ||
386 | 151 | suite = unittest.TestSuite() | ||
387 | 152 | suite.addTest(unittest.makeSuite(TestPgTestCase)) | ||
388 | 153 | suite.addTest(unittest.makeSuite(TestOptimization)) | ||
389 | 154 | return suite | ||
390 | 155 | |||
391 | 156 | if __name__ == '__main__': | ||
392 | 157 | unittest.main() | ||
393 | 158 | |||
394 | 159 | 156 | ||
395 | === modified file 'lib/canonical/launchpad/doc/canonical-config.txt' | |||
396 | --- lib/canonical/launchpad/doc/canonical-config.txt 2010-01-05 19:09:58 +0000 | |||
397 | +++ lib/canonical/launchpad/doc/canonical-config.txt 2010-10-17 19:12:52 +0000 | |||
398 | @@ -14,8 +14,10 @@ | |||
399 | 14 | simple configuration). | 14 | simple configuration). |
400 | 15 | 15 | ||
401 | 16 | >>> from canonical.config import config | 16 | >>> from canonical.config import config |
404 | 17 | >>> print config.database.rw_main_master | 17 | >>> from canonical.testing.layers import DatabaseLayer |
405 | 18 | dbname=launchpad_ftest | 18 | >>> expected = 'dbname=%s' % DatabaseLayer._db_fixture.dbname |
406 | 19 | >>> expected == config.database.rw_main_master | ||
407 | 20 | True | ||
408 | 19 | >>> config.database.db_statement_timeout is None | 21 | >>> config.database.db_statement_timeout is None |
409 | 20 | True | 22 | True |
410 | 21 | >>> config.launchpad.dbuser | 23 | >>> config.launchpad.dbuser |
411 | @@ -226,7 +228,7 @@ | |||
412 | 226 | # >>> canonical.config.config = config | 228 | # >>> canonical.config.config = config |
413 | 227 | # >>> config.filename | 229 | # >>> config.filename |
414 | 228 | # '.../configs/testrunner/launchpad-lazr.conf' | 230 | # '.../configs/testrunner/launchpad-lazr.conf' |
417 | 229 | # >>> config.dbname | 231 | # >>> config.dbname == DatabaseLayer._db_fixture.dbname |
418 | 230 | # 'launchpad_ftest' | 232 | # True |
419 | 231 | # >>> config._cache.testrunner | 233 | # >>> config._cache.testrunner |
420 | 232 | # <SectionValue for canonical 'testrunner'> | 234 | # <SectionValue for canonical 'testrunner'> |
421 | 233 | 235 | ||
422 | === modified file 'lib/canonical/launchpad/doc/old-testing.txt' | |||
423 | --- lib/canonical/launchpad/doc/old-testing.txt 2010-10-03 20:23:37 +0000 | |||
424 | +++ lib/canonical/launchpad/doc/old-testing.txt 2010-10-17 19:12:52 +0000 | |||
425 | @@ -18,11 +18,6 @@ | |||
426 | 18 | zope, we should not be testing it with the full Z3 functional test | 18 | zope, we should not be testing it with the full Z3 functional test |
427 | 19 | harness). | 19 | harness). |
428 | 20 | 20 | ||
429 | 21 | If you are wondering why we use `PgTestSetup().setUp()` and | ||
430 | 22 | `PgTestSetup.tearDown()` instead of `pgtestsetup.setUp()` or | ||
431 | 23 | `pgtestsetup.tearDown()`, it is because I'm mirroring the design used in | ||
432 | 24 | Zope3's `FunctionalTestSetup`. | ||
433 | 25 | |||
434 | 26 | canonical.functional.FunctionalTestCase | 21 | canonical.functional.FunctionalTestCase |
435 | 27 | --------------------------------------- | 22 | --------------------------------------- |
436 | 28 | 23 | ||
437 | @@ -42,11 +37,12 @@ | |||
438 | 42 | 37 | ||
439 | 43 | The setup procedure builds us a fresh, empty database | 38 | The setup procedure builds us a fresh, empty database |
440 | 44 | 39 | ||
442 | 45 | >>> PgTestSetup().setUp() | 40 | >>> fixture = PgTestSetup() |
443 | 41 | >>> fixture.setUp() | ||
444 | 46 | 42 | ||
445 | 47 | We can get connections to this database | 43 | We can get connections to this database |
446 | 48 | 44 | ||
448 | 49 | >>> connection = PgTestSetup().connect() | 45 | >>> connection = fixture.connect() |
449 | 50 | >>> cursor = connection.cursor() | 46 | >>> cursor = connection.cursor() |
450 | 51 | >>> cursor.execute("""CREATE TABLE Beer ( | 47 | >>> cursor.execute("""CREATE TABLE Beer ( |
451 | 52 | ... id serial PRIMARY KEY, name text, stamp timestamp without time zone | 48 | ... id serial PRIMARY KEY, name text, stamp timestamp without time zone |
452 | @@ -68,28 +64,29 @@ | |||
453 | 68 | When we have finished, we need to call the tearDown method which closes | 64 | When we have finished, we need to call the tearDown method which closes |
454 | 69 | all outstanding connections and destroys the database | 65 | all outstanding connections and destroys the database |
455 | 70 | 66 | ||
457 | 71 | >>> PgTestSetup().tearDown() | 67 | >>> fixture.tearDown() |
458 | 72 | 68 | ||
459 | 73 | Because the database has been destroyed, further tests will not be | 69 | Because the database has been destroyed, further tests will not be |
460 | 74 | affected. | 70 | affected. |
461 | 75 | 71 | ||
464 | 76 | >>> PgTestSetup().setUp() | 72 | >>> fixture.setUp() |
465 | 77 | >>> connection = PgTestSetup().connect() | 73 | >>> connection = fixture.connect() |
466 | 78 | >>> cursor = connection.cursor() | 74 | >>> cursor = connection.cursor() |
467 | 79 | >>> cursor.execute("CREATE TABLE Beer (id serial PRIMARY KEY, name text)") | 75 | >>> cursor.execute("CREATE TABLE Beer (id serial PRIMARY KEY, name text)") |
469 | 80 | >>> PgTestSetup().tearDown() | 76 | >>> fixture.tearDown() |
470 | 81 | 77 | ||
471 | 82 | We can also specify a different template to duplicate than the default | 78 | We can also specify a different template to duplicate than the default |
472 | 83 | clean one (template1). For example, if you need a launchpad database | 79 | clean one (template1). For example, if you need a launchpad database |
473 | 84 | containing no data, you can use `launchpad_empty` as the template. | 80 | containing no data, you can use `launchpad_empty` as the template. |
474 | 85 | 81 | ||
477 | 86 | >>> PgTestSetup('launchpad_empty').setUp() | 82 | >>> fixture = PgTestSetup('launchpad_empty') |
478 | 87 | >>> connection = PgTestSetup().connect() | 83 | >>> fixture.setUp() |
479 | 84 | >>> connection = fixture.connect() | ||
480 | 88 | >>> cursor = connection.cursor() | 85 | >>> cursor = connection.cursor() |
481 | 89 | >>> cursor.execute("SELECT COUNT(*) FROM Person") | 86 | >>> cursor.execute("SELECT COUNT(*) FROM Person") |
482 | 90 | >>> int(cursor.fetchone()[0]) | 87 | >>> int(cursor.fetchone()[0]) |
483 | 91 | 0 | 88 | 0 |
485 | 92 | >>> PgTestSetup().tearDown() | 89 | >>> fixture.tearDown() |
486 | 93 | 90 | ||
487 | 94 | We can also specify the user that we connect as to avoid connecting as the | 91 | We can also specify the user that we connect as to avoid connecting as the |
488 | 95 | PostgreSQL default user. | 92 | PostgreSQL default user. |
489 | @@ -108,14 +105,12 @@ | |||
490 | 108 | ------------------ | 105 | ------------------ |
491 | 109 | 106 | ||
492 | 110 | LaunchpadTestSetup is identical to PgTestSetup, except that it creates a | 107 | LaunchpadTestSetup is identical to PgTestSetup, except that it creates a |
501 | 111 | fresh copy of the Launchpad database filled with our sample data. This | 108 | fresh copy of the Launchpad database filled with our sample data. |
502 | 112 | class is defined in canonical.launchpad.ftests.harness. | 109 | |
503 | 113 | 110 | >>> from canonical.testing.layers import LaunchpadTestSetup | |
504 | 114 | Note that at this level, you cannot access any of the SQLBase objects | 111 | >>> fixture = LaunchpadTestSetup() |
505 | 115 | 112 | >>> fixture.setUp() | |
506 | 116 | >>> from canonical.launchpad.ftests.harness import LaunchpadTestSetup | 113 | >>> connection = fixture.connect() |
499 | 117 | >>> LaunchpadTestSetup().setUp() | ||
500 | 118 | >>> connection = LaunchpadTestSetup().connect() | ||
507 | 119 | >>> cursor = connection.cursor() | 114 | >>> cursor = connection.cursor() |
508 | 120 | >>> cursor.execute("SELECT displayname FROM person WHERE name='carlos'") | 115 | >>> cursor.execute("SELECT displayname FROM person WHERE name='carlos'") |
509 | 121 | >>> cursor.fetchone()[0] | 116 | >>> cursor.fetchone()[0] |
510 | @@ -127,7 +122,7 @@ | |||
511 | 127 | >>> cursor.fetchone()[0] | 122 | >>> cursor.fetchone()[0] |
512 | 128 | u'launchpad' | 123 | u'launchpad' |
513 | 129 | 124 | ||
515 | 130 | >>> LaunchpadTestSetup().tearDown() | 125 | >>> fixture.tearDown() |
516 | 131 | 126 | ||
517 | 132 | You can connect as a different database user using the same mechanism | 127 | You can connect as a different database user using the same mechanism |
518 | 133 | described above for PgTestSetup | 128 | described above for PgTestSetup |
519 | @@ -143,114 +138,13 @@ | |||
520 | 143 | >>> lpsetup.tearDown() | 138 | >>> lpsetup.tearDown() |
521 | 144 | 139 | ||
522 | 145 | 140 | ||
523 | 146 | LaunchpadZopelessTestSetup | ||
524 | 147 | -------------------------- | ||
525 | 148 | |||
526 | 149 | LaunchpadZopelessTestSetup builds on LaunchpadTestSetup, calling | ||
527 | 150 | initZopeless for you so you can access the SQLBase objects without needing | ||
528 | 151 | the Zope3 infrastructure. | ||
529 | 152 | |||
530 | 153 | >>> from canonical.launchpad.ftests.harness import LaunchpadZopelessTestSetup | ||
531 | 154 | >>> LaunchpadZopelessTestSetup().setUp() | ||
532 | 155 | >>> from lp.registry.model.person import Person | ||
533 | 156 | >>> stub = Person.byName('stub') | ||
534 | 157 | >>> stub.displayname | ||
535 | 158 | u'Stuart Bishop' | ||
536 | 159 | >>> stub.displayname = u'The Walrus' | ||
537 | 160 | >>> stub.displayname | ||
538 | 161 | u'The Walrus' | ||
539 | 162 | |||
540 | 163 | You have access to the zopeless transaction | ||
541 | 164 | |||
542 | 165 | >>> LaunchpadZopelessTestSetup().txn.abort() | ||
543 | 166 | >>> stub.displayname | ||
544 | 167 | u'Stuart Bishop' | ||
545 | 168 | |||
546 | 169 | And always remember to tearDown or you will victimize other tests! | ||
547 | 170 | |||
548 | 171 | >>> LaunchpadZopelessTestSetup().tearDown() | ||
549 | 172 | |||
550 | 173 | |||
551 | 174 | In general, Zopeless tests should never be running as the launchpad user. | ||
552 | 175 | You can select the user you connect as: | ||
553 | 176 | |||
554 | 177 | >>> setup = LaunchpadZopelessTestSetup(dbuser=config.librarian.dbuser) | ||
555 | 178 | >>> setup.setUp() | ||
556 | 179 | >>> from lp.registry.model.sourcepackagename import SourcePackageName | ||
557 | 180 | >>> SourcePackageName.get(1).name | ||
558 | 181 | Traceback (most recent call last): | ||
559 | 182 | ... | ||
560 | 183 | ProgrammingError: permission denied for relation sourcepackagename | ||
561 | 184 | <BLANKLINE> | ||
562 | 185 | >>> setup.tearDown() | ||
563 | 186 | |||
564 | 187 | |||
565 | 188 | LaunchpadFunctionalTestSetup | ||
566 | 189 | ---------------------------- | ||
567 | 190 | |||
568 | 191 | One with the lot. A LaunchpadTestSetup which also loads in the Zope3 | ||
569 | 192 | environment. | ||
570 | 193 | |||
571 | 194 | >>> from canonical.launchpad.ftests.harness import LaunchpadFunctionalTestSetup | ||
572 | 195 | >>> LaunchpadFunctionalTestSetup().setUp() | ||
573 | 196 | |||
574 | 197 | You have full access to the SQLBase objects | ||
575 | 198 | |||
576 | 199 | >>> mark = Person.byName('mark') | ||
577 | 200 | >>> mark.displayname | ||
578 | 201 | u'Mark Shuttleworth' | ||
579 | 202 | |||
580 | 203 | You also have access to the Zope3 component architecture, as registered | ||
581 | 204 | by ftesting.zcml | ||
582 | 205 | |||
583 | 206 | >>> from zope.app import zapi | ||
584 | 207 | >>> from zope.sendmail.interfaces import IMailer | ||
585 | 208 | >>> zapi.getUtility(IMailer, 'smtp') is not None | ||
586 | 209 | True | ||
587 | 210 | |||
588 | 211 | >>> LaunchpadFunctionalTestSetup().tearDown() | ||
589 | 212 | |||
590 | 213 | You can change the user that the tests connect as: | ||
591 | 214 | |||
592 | 215 | XXX 2008-05-29 jamesh: | ||
593 | 216 | Using LaunchpadFunctionalLayer for non-webapp db users is generally | ||
594 | 217 | a sign of a bug. These bits of code should generally be using | ||
595 | 218 | LaunchpadZopelessLayer. | ||
596 | 219 | |||
597 | 220 | ##>>> setup = LaunchpadFunctionalTestSetup(dbuser=config.librarian.dbuser) | ||
598 | 221 | ##>>> setup.setUp() | ||
599 | 222 | ##>>> connection = setup.connect() | ||
600 | 223 | ##>>> cursor = connection.cursor() | ||
601 | 224 | ##>>> cursor.execute('SELECT current_user') | ||
602 | 225 | ##>>> cursor.fetchone()[0] | ||
603 | 226 | ##u'librarian' | ||
604 | 227 | ##>>> SourcePackageName.get(1).name | ||
605 | 228 | ##Traceback (most recent call last): | ||
606 | 229 | ##... | ||
607 | 230 | ##ProgrammingError: permission denied ... | ||
608 | 231 | ##>>> setup.tearDown() | ||
609 | 232 | |||
610 | 233 | And the next test will be unaffected: | ||
611 | 234 | |||
612 | 235 | >>> setup = LaunchpadFunctionalTestSetup() | ||
613 | 236 | >>> setup.setUp() | ||
614 | 237 | >>> connection = setup.connect() | ||
615 | 238 | >>> cursor = connection.cursor() | ||
616 | 239 | >>> cursor.execute('SELECT current_user') | ||
617 | 240 | >>> cursor.fetchone()[0] | ||
618 | 241 | u'launchpad' | ||
619 | 242 | >>> SourcePackageName.get(1).name | ||
620 | 243 | u'mozilla-firefox' | ||
621 | 244 | >>> setup.tearDown() | ||
622 | 245 | |||
623 | 246 | |||
624 | 247 | LibrarianTestSetup | 141 | LibrarianTestSetup |
625 | 248 | ------------------ | 142 | ------------------ |
626 | 249 | 143 | ||
627 | 250 | Code that needs to access the Librarian can do so easily. Note that | 144 | Code that needs to access the Librarian can do so easily. Note that |
628 | 251 | LibrarianTestSetup requires the Launchpad database to be available, and | 145 | LibrarianTestSetup requires the Launchpad database to be available, and |
629 | 252 | thus requires LaunchpadTestSetup or similar to be used in tandam. | 146 | thus requires LaunchpadTestSetup or similar to be used in tandam. |
631 | 253 | You probably really want LaunchpadFunctionalTestSetup so you can access | 147 | You probably really want LaunchpadFunctionalLayer so you can access |
632 | 254 | the Librarian as a Utility. | 148 | the Librarian as a Utility. |
633 | 255 | 149 | ||
634 | 256 | >>> from canonical.librarian.testing.server import LibrarianTestSetup | 150 | >>> from canonical.librarian.testing.server import LibrarianTestSetup |
635 | @@ -259,7 +153,6 @@ | |||
636 | 259 | >>> from canonical.librarian.interfaces import ILibrarianClient | 153 | >>> from canonical.librarian.interfaces import ILibrarianClient |
637 | 260 | >>> from StringIO import StringIO | 154 | >>> from StringIO import StringIO |
638 | 261 | 155 | ||
639 | 262 | >>> LaunchpadFunctionalTestSetup().setUp() | ||
640 | 263 | >>> librarian = LibrarianTestSetup() | 156 | >>> librarian = LibrarianTestSetup() |
641 | 264 | >>> librarian.setUp() | 157 | >>> librarian.setUp() |
642 | 265 | >>> login(ANONYMOUS) | 158 | >>> login(ANONYMOUS) |
643 | @@ -285,7 +178,6 @@ | |||
644 | 285 | True | 178 | True |
645 | 286 | 179 | ||
646 | 287 | >>> librarian.tearDown() | 180 | >>> librarian.tearDown() |
647 | 288 | >>> LaunchpadFunctionalTestSetup().tearDown() | ||
648 | 289 | 181 | ||
649 | 290 | >>> from canonical.testing import reset_logging | 182 | >>> from canonical.testing import reset_logging |
650 | 291 | >>> reset_logging() | 183 | >>> reset_logging() |
651 | 292 | 184 | ||
652 | === modified file 'lib/canonical/launchpad/doc/security-proxies.txt' | |||
653 | --- lib/canonical/launchpad/doc/security-proxies.txt 2010-10-09 16:36:22 +0000 | |||
654 | +++ lib/canonical/launchpad/doc/security-proxies.txt 2010-10-17 19:12:52 +0000 | |||
655 | @@ -6,13 +6,10 @@ | |||
656 | 6 | 6 | ||
657 | 7 | First, some imports and set up:: | 7 | First, some imports and set up:: |
658 | 8 | 8 | ||
659 | 9 | >>> from canonical.launchpad.ftests.harness import LaunchpadFunctionalTestSetup | ||
660 | 10 | >>> from zope.component import getUtility | 9 | >>> from zope.component import getUtility |
661 | 11 | >>> from lp.registry.interfaces.person import IPersonSet | 10 | >>> from lp.registry.interfaces.person import IPersonSet |
662 | 12 | >>> from lp.registry.model.person import Person | 11 | >>> from lp.registry.model.person import Person |
663 | 13 | 12 | ||
664 | 14 | >>> LaunchpadFunctionalTestSetup().setUp() | ||
665 | 15 | |||
666 | 16 | Get a proxied and unproxied person object for the same person, and demonstrate | 13 | Get a proxied and unproxied person object for the same person, and demonstrate |
667 | 17 | working comparisons:: | 14 | working comparisons:: |
668 | 18 | 15 | ||
669 | @@ -57,8 +54,3 @@ | |||
670 | 57 | True | 54 | True |
671 | 58 | >>> hoary.status is SeriesStatus.DEVELOPMENT | 55 | >>> hoary.status is SeriesStatus.DEVELOPMENT |
672 | 59 | False | 56 | False |
673 | 60 | |||
674 | 61 | Finally, tear down the test: | ||
675 | 62 | |||
676 | 63 | >>> LaunchpadFunctionalTestSetup().tearDown() | ||
677 | 64 | |||
678 | 65 | 57 | ||
679 | === removed file 'lib/canonical/launchpad/ftests/harness.py' | |||
680 | --- lib/canonical/launchpad/ftests/harness.py 2010-10-04 19:50:45 +0000 | |||
681 | +++ lib/canonical/launchpad/ftests/harness.py 1970-01-01 00:00:00 +0000 | |||
682 | @@ -1,84 +0,0 @@ | |||
683 | 1 | # Copyright 2009 Canonical Ltd. This software is licensed under the | ||
684 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
685 | 3 | |||
686 | 4 | """ | ||
687 | 5 | Launchpad functional test helpers. | ||
688 | 6 | |||
689 | 7 | This file needs to be refactored, moving its functionality into | ||
690 | 8 | canonical.testing | ||
691 | 9 | """ | ||
692 | 10 | |||
693 | 11 | __metaclass__ = type | ||
694 | 12 | |||
695 | 13 | |||
696 | 14 | from zope.app.testing.functional import FunctionalTestSetup | ||
697 | 15 | |||
698 | 16 | from canonical.database.sqlbase import ZopelessTransactionManager | ||
699 | 17 | from canonical.ftests.pgsql import PgTestSetup | ||
700 | 18 | from canonical.lp import initZopeless | ||
701 | 19 | from canonical.testing.layers import ( | ||
702 | 20 | FunctionalLayer, | ||
703 | 21 | ZopelessLayer, | ||
704 | 22 | ) | ||
705 | 23 | from canonical.testing.layers import ( | ||
706 | 24 | disconnect_stores, | ||
707 | 25 | reconnect_stores, | ||
708 | 26 | ) | ||
709 | 27 | |||
710 | 28 | |||
711 | 29 | __all__ = [ | ||
712 | 30 | 'LaunchpadTestSetup', 'LaunchpadZopelessTestSetup', | ||
713 | 31 | 'LaunchpadFunctionalTestSetup', | ||
714 | 32 | ] | ||
715 | 33 | |||
716 | 34 | |||
717 | 35 | class LaunchpadTestSetup(PgTestSetup): | ||
718 | 36 | template = 'launchpad_ftest_template' | ||
719 | 37 | dbname = 'launchpad_ftest' # Needs to match ftesting.zcml | ||
720 | 38 | dbuser = 'launchpad' | ||
721 | 39 | |||
722 | 40 | |||
723 | 41 | class LaunchpadZopelessTestSetup(LaunchpadTestSetup): | ||
724 | 42 | txn = ZopelessTransactionManager | ||
725 | 43 | def setUp(self, dbuser=None): | ||
726 | 44 | assert ZopelessTransactionManager._installed is None, \ | ||
727 | 45 | 'Last test using Zopeless failed to tearDown correctly' | ||
728 | 46 | super(LaunchpadZopelessTestSetup, self).setUp() | ||
729 | 47 | if self.host is not None: | ||
730 | 48 | raise NotImplementedError('host not supported yet') | ||
731 | 49 | if self.port is not None: | ||
732 | 50 | raise NotImplementedError('port not supported yet') | ||
733 | 51 | if dbuser is not None: | ||
734 | 52 | self.dbuser = dbuser | ||
735 | 53 | initZopeless(dbname=self.dbname, dbuser=self.dbuser) | ||
736 | 54 | |||
737 | 55 | def tearDown(self): | ||
738 | 56 | LaunchpadZopelessTestSetup.txn.uninstall() | ||
739 | 57 | assert ZopelessTransactionManager._installed is None, \ | ||
740 | 58 | 'Failed to tearDown Zopeless correctly' | ||
741 | 59 | |||
742 | 60 | |||
743 | 61 | class LaunchpadFunctionalTestSetup(LaunchpadTestSetup): | ||
744 | 62 | def _checkLayerInvariants(self): | ||
745 | 63 | assert FunctionalLayer.isSetUp or ZopelessLayer.isSetUp, """ | ||
746 | 64 | FunctionalTestSetup invoked at an inappropriate time. | ||
747 | 65 | May only be invoked in the FunctionalLayer or ZopelessLayer | ||
748 | 66 | """ | ||
749 | 67 | |||
750 | 68 | def setUp(self, dbuser=None): | ||
751 | 69 | self._checkLayerInvariants() | ||
752 | 70 | if dbuser is not None: | ||
753 | 71 | self.dbuser = dbuser | ||
754 | 72 | assert self.dbuser == 'launchpad', ( | ||
755 | 73 | "Non-default user names should probably be using " | ||
756 | 74 | "script layer or zopeless layer.") | ||
757 | 75 | disconnect_stores() | ||
758 | 76 | super(LaunchpadFunctionalTestSetup, self).setUp() | ||
759 | 77 | FunctionalTestSetup().setUp() | ||
760 | 78 | reconnect_stores() | ||
761 | 79 | |||
762 | 80 | def tearDown(self): | ||
763 | 81 | self._checkLayerInvariants() | ||
764 | 82 | FunctionalTestSetup().tearDown() | ||
765 | 83 | disconnect_stores() | ||
766 | 84 | super(LaunchpadFunctionalTestSetup, self).tearDown() | ||
767 | 85 | 0 | ||
768 | === modified file 'lib/canonical/launchpad/pagetests/standalone/xx-dbpolicy.txt' | |||
769 | --- lib/canonical/launchpad/pagetests/standalone/xx-dbpolicy.txt 2010-01-13 13:50:39 +0000 | |||
770 | +++ lib/canonical/launchpad/pagetests/standalone/xx-dbpolicy.txt 2010-10-17 19:12:52 +0000 | |||
771 | @@ -20,9 +20,11 @@ | |||
772 | 20 | >>> from zope.component import getUtility | 20 | >>> from zope.component import getUtility |
773 | 21 | >>> from canonical.launchpad.webapp.interfaces import ( | 21 | >>> from canonical.launchpad.webapp.interfaces import ( |
774 | 22 | ... IStoreSelector, MAIN_STORE, MASTER_FLAVOR, SLAVE_FLAVOR) | 22 | ... IStoreSelector, MAIN_STORE, MASTER_FLAVOR, SLAVE_FLAVOR) |
775 | 23 | >>> from canonical.testing.layers import DatabaseLayer | ||
776 | 23 | >>> master = getUtility(IStoreSelector).get(MAIN_STORE, MASTER_FLAVOR) | 24 | >>> master = getUtility(IStoreSelector).get(MAIN_STORE, MASTER_FLAVOR) |
779 | 24 | >>> master.execute("SELECT current_database()").get_one()[0] | 25 | >>> dbname = DatabaseLayer._db_fixture.dbname |
780 | 25 | u'launchpad_ftest' | 26 | >>> dbname == master.execute("SELECT current_database()").get_one()[0] |
781 | 27 | True | ||
782 | 26 | >>> slave = getUtility(IStoreSelector).get(MAIN_STORE, SLAVE_FLAVOR) | 28 | >>> slave = getUtility(IStoreSelector).get(MAIN_STORE, SLAVE_FLAVOR) |
783 | 27 | >>> slave.execute("SELECT current_database()").get_one()[0] | 29 | >>> slave.execute("SELECT current_database()").get_one()[0] |
784 | 28 | u'launchpad_empty' | 30 | u'launchpad_empty' |
785 | @@ -47,7 +49,7 @@ | |||
786 | 47 | 49 | ||
787 | 48 | >>> def whichdb(browser): | 50 | >>> def whichdb(browser): |
788 | 49 | ... dbname = extract_text(find_tag_by_id(browser.contents, 'dbname')) | 51 | ... dbname = extract_text(find_tag_by_id(browser.contents, 'dbname')) |
790 | 50 | ... if dbname == 'launchpad_ftest': | 52 | ... if dbname == DatabaseLayer._db_fixture.dbname: |
791 | 51 | ... return 'MASTER' | 53 | ... return 'MASTER' |
792 | 52 | ... elif dbname == 'launchpad_empty': | 54 | ... elif dbname == 'launchpad_empty': |
793 | 53 | ... return 'SLAVE' | 55 | ... return 'SLAVE' |
794 | 54 | 56 | ||
795 | === modified file 'lib/canonical/launchpad/tests/test_sampledata.py' | |||
796 | --- lib/canonical/launchpad/tests/test_sampledata.py 2010-09-22 13:26:50 +0000 | |||
797 | +++ lib/canonical/launchpad/tests/test_sampledata.py 2010-10-17 19:12:52 +0000 | |||
798 | @@ -12,7 +12,6 @@ | |||
799 | 12 | __all__ = [] | 12 | __all__ = [] |
800 | 13 | 13 | ||
801 | 14 | import subprocess | 14 | import subprocess |
802 | 15 | import unittest | ||
803 | 16 | 15 | ||
804 | 17 | from canonical.testing.layers import DatabaseLayer | 16 | from canonical.testing.layers import DatabaseLayer |
805 | 18 | from lp.testing import TestCase | 17 | from lp.testing import TestCase |
806 | @@ -37,14 +36,11 @@ | |||
807 | 37 | cmd = ( | 36 | cmd = ( |
808 | 38 | "pg_dump --format=c --compress=0 --no-privileges --no-owner" | 37 | "pg_dump --format=c --compress=0 --no-privileges --no-owner" |
809 | 39 | " --schema=public %s | pg_restore --clean" | 38 | " --schema=public %s | pg_restore --clean" |
811 | 40 | " --exit-on-error --dbname=launchpad_ftest" % source_dbname) | 39 | " --exit-on-error --dbname=%s" % ( |
812 | 40 | source_dbname, DatabaseLayer._db_fixture.dbname)) | ||
813 | 41 | proc = subprocess.Popen( | 41 | proc = subprocess.Popen( |
814 | 42 | cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, | 42 | cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, |
815 | 43 | stdin=subprocess.PIPE) | 43 | stdin=subprocess.PIPE) |
816 | 44 | (stdout, stderr) = proc.communicate() | 44 | (stdout, stderr) = proc.communicate() |
817 | 45 | rv = proc.wait() | 45 | rv = proc.wait() |
818 | 46 | self.failUnlessEqual(rv, 0, "Dump/Restore failed: %s" % stdout) | 46 | self.failUnlessEqual(rv, 0, "Dump/Restore failed: %s" % stdout) |
819 | 47 | |||
820 | 48 | |||
821 | 49 | def test_suite(): | ||
822 | 50 | return unittest.TestLoader().loadTestsFromName(__name__) | ||
823 | 51 | 47 | ||
824 | === modified file 'lib/canonical/launchpad/webapp/ftests/test_adapter.txt' | |||
825 | --- lib/canonical/launchpad/webapp/ftests/test_adapter.txt 2010-09-17 00:53:33 +0000 | |||
826 | +++ lib/canonical/launchpad/webapp/ftests/test_adapter.txt 2010-10-17 19:12:52 +0000 | |||
827 | @@ -18,14 +18,18 @@ | |||
828 | 18 | >>> from canonical.launchpad.webapp.adapter import ( | 18 | >>> from canonical.launchpad.webapp.adapter import ( |
829 | 19 | ... clear_request_started, get_request_statements, | 19 | ... clear_request_started, get_request_statements, |
830 | 20 | ... set_request_started) | 20 | ... set_request_started) |
831 | 21 | >>> from canonical.testing.layers import DatabaseLayer | ||
832 | 21 | >>> from lp.services.timeline.requesttimeline import get_request_timeline | 22 | >>> from lp.services.timeline.requesttimeline import get_request_timeline |
833 | 22 | 23 | ||
834 | 23 | There are several possible database connections available via the | 24 | There are several possible database connections available via the |
835 | 24 | IStoreSelector utility. | 25 | IStoreSelector utility. |
836 | 25 | 26 | ||
837 | 26 | >>> store = getUtility(IStoreSelector).get(MAIN_STORE, MASTER_FLAVOR) | 27 | >>> store = getUtility(IStoreSelector).get(MAIN_STORE, MASTER_FLAVOR) |
840 | 27 | >>> print store.execute("SELECT current_database()").get_one()[0] | 28 | >>> dbname = DatabaseLayer._db_fixture.dbname |
841 | 28 | launchpad_ftest | 29 | >>> active_name = store.execute("SELECT current_database()").get_one()[0] |
842 | 30 | >>> if active_name != dbname: print '%s != %s' % (active_name, dbname) | ||
843 | 31 | >>> active_name == dbname | ||
844 | 32 | True | ||
845 | 29 | 33 | ||
846 | 30 | 34 | ||
847 | 31 | Statement Logging | 35 | Statement Logging |
848 | 32 | 36 | ||
849 | === modified file 'lib/canonical/lp/ftests/test_zopeless.py' | |||
850 | --- lib/canonical/lp/ftests/test_zopeless.py 2010-10-04 19:50:45 +0000 | |||
851 | +++ lib/canonical/lp/ftests/test_zopeless.py 2010-10-17 19:12:52 +0000 | |||
852 | @@ -14,9 +14,11 @@ | |||
853 | 14 | from sqlobject import StringCol, IntCol | 14 | from sqlobject import StringCol, IntCol |
854 | 15 | 15 | ||
855 | 16 | from canonical.database.sqlbase import SQLBase, alreadyInstalledMsg, cursor | 16 | from canonical.database.sqlbase import SQLBase, alreadyInstalledMsg, cursor |
856 | 17 | from canonical.ftests.pgsql import PgTestSetup | ||
857 | 18 | from canonical.lp import initZopeless | 17 | from canonical.lp import initZopeless |
859 | 19 | from canonical.testing.layers import LaunchpadScriptLayer | 18 | from canonical.testing.layers import ( |
860 | 19 | DatabaseLayer, | ||
861 | 20 | LaunchpadScriptLayer, | ||
862 | 21 | ) | ||
863 | 20 | 22 | ||
864 | 21 | 23 | ||
865 | 22 | class MoreBeer(SQLBase): | 24 | class MoreBeer(SQLBase): |
866 | @@ -28,6 +30,7 @@ | |||
867 | 28 | 30 | ||
868 | 29 | 31 | ||
869 | 30 | class TestInitZopeless(unittest.TestCase): | 32 | class TestInitZopeless(unittest.TestCase): |
870 | 33 | |||
871 | 31 | layer = LaunchpadScriptLayer | 34 | layer = LaunchpadScriptLayer |
872 | 32 | 35 | ||
873 | 33 | def test_initZopelessTwice(self): | 36 | def test_initZopelessTwice(self): |
874 | @@ -47,10 +50,11 @@ | |||
875 | 47 | # Calling initZopeless with the same arguments twice should return | 50 | # Calling initZopeless with the same arguments twice should return |
876 | 48 | # the exact same object twice, but also emit a warning. | 51 | # the exact same object twice, but also emit a warning. |
877 | 49 | try: | 52 | try: |
882 | 50 | tm1 = initZopeless(dbname=PgTestSetup().dbname, dbhost='', | 53 | dbname = DatabaseLayer._db_fixture.dbname |
883 | 51 | dbuser='launchpad') | 54 | tm1 = initZopeless( |
884 | 52 | tm2 = initZopeless(dbname=PgTestSetup().dbname, dbhost='', | 55 | dbname=dbname, dbhost='', dbuser='launchpad') |
885 | 53 | dbuser='launchpad') | 56 | tm2 = initZopeless( |
886 | 57 | dbname=dbname, dbhost='', dbuser='launchpad') | ||
887 | 54 | self.failUnless(tm1 is tm2) | 58 | self.failUnless(tm1 is tm2) |
888 | 55 | self.failUnless(self.warned) | 59 | self.failUnless(self.warned) |
889 | 56 | finally: | 60 | finally: |
890 | @@ -65,10 +69,11 @@ | |||
891 | 65 | 69 | ||
892 | 66 | 70 | ||
893 | 67 | class TestZopeless(unittest.TestCase): | 71 | class TestZopeless(unittest.TestCase): |
894 | 72 | |||
895 | 68 | layer = LaunchpadScriptLayer | 73 | layer = LaunchpadScriptLayer |
896 | 69 | 74 | ||
897 | 70 | def setUp(self): | 75 | def setUp(self): |
899 | 71 | self.tm = initZopeless(dbname=PgTestSetup().dbname, | 76 | self.tm = initZopeless(dbname=DatabaseLayer._db_fixture.dbname, |
900 | 72 | dbuser='launchpad') | 77 | dbuser='launchpad') |
901 | 73 | 78 | ||
902 | 74 | c = cursor() | 79 | c = cursor() |
903 | @@ -182,7 +187,7 @@ | |||
904 | 182 | self.tm.commit() | 187 | self.tm.commit() |
905 | 183 | 188 | ||
906 | 184 | # Make another change from a non-SQLObject connection, and commit that | 189 | # Make another change from a non-SQLObject connection, and commit that |
908 | 185 | conn = psycopg2.connect('dbname=' + PgTestSetup().dbname) | 190 | conn = psycopg2.connect('dbname=' + DatabaseLayer._db_fixture.dbname) |
909 | 186 | cur = conn.cursor() | 191 | cur = conn.cursor() |
910 | 187 | cur.execute("BEGIN TRANSACTION;") | 192 | cur.execute("BEGIN TRANSACTION;") |
911 | 188 | cur.execute("UPDATE MoreBeer SET rating=4 " | 193 | cur.execute("UPDATE MoreBeer SET rating=4 " |
912 | @@ -202,7 +207,7 @@ | |||
913 | 202 | >>> isZopeless() | 207 | >>> isZopeless() |
914 | 203 | False | 208 | False |
915 | 204 | 209 | ||
917 | 205 | >>> tm = initZopeless(dbname=PgTestSetup().dbname, | 210 | >>> tm = initZopeless(dbname=DatabaseLayer._db_fixture.dbname, |
918 | 206 | ... dbhost='', dbuser='launchpad') | 211 | ... dbhost='', dbuser='launchpad') |
919 | 207 | >>> isZopeless() | 212 | >>> isZopeless() |
920 | 208 | True | 213 | True |
921 | 209 | 214 | ||
922 | === modified file 'lib/canonical/testing/ftests/test_layers.py' | |||
923 | --- lib/canonical/testing/ftests/test_layers.py 2010-07-26 13:18:18 +0000 | |||
924 | +++ lib/canonical/testing/ftests/test_layers.py 2010-10-17 19:12:52 +0000 | |||
925 | @@ -20,16 +20,27 @@ | |||
926 | 20 | from zope.component import getUtility, ComponentLookupError | 20 | from zope.component import getUtility, ComponentLookupError |
927 | 21 | 21 | ||
928 | 22 | from canonical.config import config, dbconfig | 22 | from canonical.config import config, dbconfig |
929 | 23 | from canonical.launchpad.ftests.harness import LaunchpadTestSetup | ||
930 | 24 | from lazr.config import as_host_port | 23 | from lazr.config import as_host_port |
931 | 25 | from canonical.librarian.client import LibrarianClient, UploadFailed | 24 | from canonical.librarian.client import LibrarianClient, UploadFailed |
932 | 26 | from canonical.librarian.interfaces import ILibrarianClient | 25 | from canonical.librarian.interfaces import ILibrarianClient |
933 | 27 | from canonical.lazr.pidfile import pidfile_path | 26 | from canonical.lazr.pidfile import pidfile_path |
934 | 28 | from canonical.testing.layers import ( | 27 | from canonical.testing.layers import ( |
939 | 29 | AppServerLayer, BaseLayer, DatabaseLayer, FunctionalLayer, | 28 | AppServerLayer, |
940 | 30 | LaunchpadFunctionalLayer, LaunchpadLayer, LaunchpadScriptLayer, | 29 | BaseLayer, |
941 | 31 | LaunchpadZopelessLayer, LayerInvariantError, LayerIsolationError, | 30 | DatabaseLayer, |
942 | 32 | LayerProcessController, LibrarianLayer, MemcachedLayer, ZopelessLayer) | 31 | FunctionalLayer, |
943 | 32 | LaunchpadFunctionalLayer, | ||
944 | 33 | LaunchpadLayer, | ||
945 | 34 | LaunchpadScriptLayer, | ||
946 | 35 | LaunchpadTestSetup, | ||
947 | 36 | LaunchpadZopelessLayer, | ||
948 | 37 | LayerInvariantError, | ||
949 | 38 | LayerIsolationError, | ||
950 | 39 | LayerProcessController, | ||
951 | 40 | LibrarianLayer, | ||
952 | 41 | MemcachedLayer, | ||
953 | 42 | ZopelessLayer, | ||
954 | 43 | ) | ||
955 | 33 | from lp.services.memcache.client import memcache_client_factory | 44 | from lp.services.memcache.client import memcache_client_factory |
956 | 34 | 45 | ||
957 | 35 | class BaseTestCase(unittest.TestCase): | 46 | class BaseTestCase(unittest.TestCase): |
958 | @@ -123,22 +134,13 @@ | |||
959 | 123 | ) | 134 | ) |
960 | 124 | 135 | ||
961 | 125 | def testLaunchpadDbAvailable(self): | 136 | def testLaunchpadDbAvailable(self): |
978 | 126 | try: | 137 | if not self.want_launchpad_database: |
979 | 127 | con = DatabaseLayer.connect() | 138 | self.assertEqual(None, DatabaseLayer._db_fixture) |
980 | 128 | cur = con.cursor() | 139 | return |
981 | 129 | cur.execute("SELECT id FROM Person LIMIT 1") | 140 | con = DatabaseLayer.connect() |
982 | 130 | if cur.fetchone() is not None: | 141 | cur = con.cursor() |
983 | 131 | self.failUnless( | 142 | cur.execute("SELECT id FROM Person LIMIT 1") |
984 | 132 | self.want_launchpad_database, | 143 | self.assertNotEqual(None, cur.fetchone()) |
969 | 133 | 'Launchpad database should not be available.' | ||
970 | 134 | ) | ||
971 | 135 | return | ||
972 | 136 | except psycopg2.Error: | ||
973 | 137 | pass | ||
974 | 138 | self.failIf( | ||
975 | 139 | self.want_launchpad_database, | ||
976 | 140 | 'Launchpad database should be available but is not.' | ||
977 | 141 | ) | ||
985 | 142 | 144 | ||
986 | 143 | def testMemcachedWorking(self): | 145 | def testMemcachedWorking(self): |
987 | 144 | client = MemcachedLayer.client or memcache_client_factory() | 146 | client = MemcachedLayer.client or memcache_client_factory() |
988 | @@ -424,6 +426,9 @@ | |||
989 | 424 | # The database should be reset by the test invariants. | 426 | # The database should be reset by the test invariants. |
990 | 425 | LayerProcessController.startAppServer() | 427 | LayerProcessController.startAppServer() |
991 | 426 | LayerProcessController.postTestInvariants() | 428 | LayerProcessController.postTestInvariants() |
992 | 429 | # XXX: Robert Collins 2010-10-17 bug=661967 - this isn't a reset, its | ||
993 | 430 | # a flag that it *needs* a reset, which is actually quite different; | ||
994 | 431 | # the lack of a teardown will leak daabases. | ||
995 | 427 | self.assertEquals(True, LaunchpadTestSetup()._reset_db) | 432 | self.assertEquals(True, LaunchpadTestSetup()._reset_db) |
996 | 428 | 433 | ||
997 | 429 | 434 | ||
998 | 430 | 435 | ||
999 | === modified file 'lib/canonical/testing/layers.py' | |||
1000 | --- lib/canonical/testing/layers.py 2010-10-05 13:25:01 +0000 | |||
1001 | +++ lib/canonical/testing/layers.py 2010-10-17 19:12:52 +0000 | |||
1002 | @@ -35,6 +35,7 @@ | |||
1003 | 35 | 'LaunchpadFunctionalLayer', | 35 | 'LaunchpadFunctionalLayer', |
1004 | 36 | 'LaunchpadLayer', | 36 | 'LaunchpadLayer', |
1005 | 37 | 'LaunchpadScriptLayer', | 37 | 'LaunchpadScriptLayer', |
1006 | 38 | 'LaunchpadTestSetup', | ||
1007 | 38 | 'LaunchpadZopelessLayer', | 39 | 'LaunchpadZopelessLayer', |
1008 | 39 | 'LayerInvariantError', | 40 | 'LayerInvariantError', |
1009 | 40 | 'LayerIsolationError', | 41 | 'LayerIsolationError', |
1010 | @@ -92,6 +93,7 @@ | |||
1011 | 92 | from zope.server.logger.pythonlogger import PythonLogger | 93 | from zope.server.logger.pythonlogger import PythonLogger |
1012 | 93 | from zope.testing.testrunner.runner import FakeInputContinueGenerator | 94 | from zope.testing.testrunner.runner import FakeInputContinueGenerator |
1013 | 94 | 95 | ||
1014 | 96 | from canonical.ftests.pgsql import PgTestSetup | ||
1015 | 95 | from canonical.launchpad.webapp.vhosts import allvhosts | 97 | from canonical.launchpad.webapp.vhosts import allvhosts |
1016 | 96 | from canonical.lazr import pidfile | 98 | from canonical.lazr import pidfile |
1017 | 97 | from canonical.config import CanonicalConfig, config, dbconfig | 99 | from canonical.config import CanonicalConfig, config, dbconfig |
1018 | @@ -264,12 +266,14 @@ | |||
1019 | 264 | if not BaseLayer.persist_test_services: | 266 | if not BaseLayer.persist_test_services: |
1020 | 265 | kill_by_pidfile(MemcachedLayer.getPidFile(), num_polls=0) | 267 | kill_by_pidfile(MemcachedLayer.getPidFile(), num_polls=0) |
1021 | 266 | # Kill any database left lying around from a previous test run. | 268 | # Kill any database left lying around from a previous test run. |
1022 | 269 | db_fixture = LaunchpadTestSetup() | ||
1023 | 267 | try: | 270 | try: |
1025 | 268 | DatabaseLayer.connect().close() | 271 | db_fixture.connect().close() |
1026 | 269 | except psycopg2.Error: | 272 | except psycopg2.Error: |
1027 | 273 | # We assume this means 'no test database exists.' | ||
1028 | 270 | pass | 274 | pass |
1029 | 271 | else: | 275 | else: |
1031 | 272 | DatabaseLayer._dropDb() | 276 | db_fixture.dropDb() |
1032 | 273 | 277 | ||
1033 | 274 | @classmethod | 278 | @classmethod |
1034 | 275 | @profiled | 279 | @profiled |
1035 | @@ -693,19 +697,19 @@ | |||
1036 | 693 | _reset_between_tests = True | 697 | _reset_between_tests = True |
1037 | 694 | 698 | ||
1038 | 695 | _is_setup = False | 699 | _is_setup = False |
1039 | 700 | _db_fixture = None | ||
1040 | 696 | 701 | ||
1041 | 697 | @classmethod | 702 | @classmethod |
1042 | 698 | @profiled | 703 | @profiled |
1043 | 699 | def setUp(cls): | 704 | def setUp(cls): |
1044 | 700 | cls._is_setup = True | 705 | cls._is_setup = True |
1052 | 701 | DatabaseLayer.force_dirty_database() | 706 | # Read the sequences we'll need from the test template database. |
1053 | 702 | # Imported here to avoid circular import issues. This | 707 | reset_sequences_sql = LaunchpadTestSetup( |
1047 | 703 | # functionality should be migrated into this module at some | ||
1048 | 704 | # point. -- StuartBishop 20060712 | ||
1049 | 705 | from canonical.launchpad.ftests.harness import LaunchpadTestSetup | ||
1050 | 706 | LaunchpadTestSetup().tearDown() | ||
1051 | 707 | DatabaseLayer._reset_sequences_sql = LaunchpadTestSetup( | ||
1054 | 708 | dbname='launchpad_ftest_template').generateResetSequencesSQL() | 708 | dbname='launchpad_ftest_template').generateResetSequencesSQL() |
1055 | 709 | cls._db_fixture = LaunchpadTestSetup( | ||
1056 | 710 | reset_sequences_sql=reset_sequences_sql) | ||
1057 | 711 | cls.force_dirty_database() | ||
1058 | 712 | cls._db_fixture.tearDown() | ||
1059 | 709 | 713 | ||
1060 | 710 | @classmethod | 714 | @classmethod |
1061 | 711 | @profiled | 715 | @profiled |
1062 | @@ -716,32 +720,22 @@ | |||
1063 | 716 | # Don't leave the DB lying around or it might break tests | 720 | # Don't leave the DB lying around or it might break tests |
1064 | 717 | # that depend on it not being there on startup, such as found | 721 | # that depend on it not being there on startup, such as found |
1065 | 718 | # in test_layers.py | 722 | # in test_layers.py |
1073 | 719 | DatabaseLayer.force_dirty_database() | 723 | cls.force_dirty_database() |
1074 | 720 | # Imported here to avoid circular import issues. This | 724 | cls._db_fixture.tearDown() |
1075 | 721 | # functionality should be migrated into this module at some | 725 | cls._db_fixture = None |
1069 | 722 | # point. -- StuartBishop 20060712 | ||
1070 | 723 | from canonical.launchpad.ftests.harness import LaunchpadTestSetup | ||
1071 | 724 | LaunchpadTestSetup().tearDown() | ||
1072 | 725 | DatabaseLayer._reset_sequences_sql = None | ||
1076 | 726 | 726 | ||
1077 | 727 | @classmethod | 727 | @classmethod |
1078 | 728 | @profiled | 728 | @profiled |
1079 | 729 | def testSetUp(cls): | 729 | def testSetUp(cls): |
1088 | 730 | # Imported here to avoid circular import issues. This | 730 | if cls._reset_between_tests: |
1089 | 731 | # functionality should be migrated into this module at some | 731 | cls._db_fixture.setUp() |
1082 | 732 | # point. -- StuartBishop 20060712 | ||
1083 | 733 | from canonical.launchpad.ftests.harness import LaunchpadTestSetup | ||
1084 | 734 | if DatabaseLayer._reset_between_tests: | ||
1085 | 735 | LaunchpadTestSetup( | ||
1086 | 736 | reset_sequences_sql=DatabaseLayer._reset_sequences_sql | ||
1087 | 737 | ).setUp() | ||
1090 | 738 | # Ensure that the database is connectable. Because we might have | 732 | # Ensure that the database is connectable. Because we might have |
1091 | 739 | # just created it, keep trying for a few seconds incase PostgreSQL | 733 | # just created it, keep trying for a few seconds incase PostgreSQL |
1092 | 740 | # is taking its time getting its house in order. | 734 | # is taking its time getting its house in order. |
1093 | 741 | attempts = 60 | 735 | attempts = 60 |
1094 | 742 | for count in range(0, attempts): | 736 | for count in range(0, attempts): |
1095 | 743 | try: | 737 | try: |
1097 | 744 | DatabaseLayer.connect().close() | 738 | cls.connect().close() |
1098 | 745 | except psycopg2.Error: | 739 | except psycopg2.Error: |
1099 | 746 | if count == attempts - 1: | 740 | if count == attempts - 1: |
1100 | 747 | raise | 741 | raise |
1101 | @@ -749,24 +743,20 @@ | |||
1102 | 749 | else: | 743 | else: |
1103 | 750 | break | 744 | break |
1104 | 751 | 745 | ||
1107 | 752 | if DatabaseLayer.use_mockdb is True: | 746 | if cls.use_mockdb is True: |
1108 | 753 | DatabaseLayer.installMockDb() | 747 | cls.installMockDb() |
1109 | 754 | 748 | ||
1110 | 755 | @classmethod | 749 | @classmethod |
1111 | 756 | @profiled | 750 | @profiled |
1112 | 757 | def testTearDown(cls): | 751 | def testTearDown(cls): |
1115 | 758 | if DatabaseLayer.use_mockdb is True: | 752 | if cls.use_mockdb is True: |
1116 | 759 | DatabaseLayer.uninstallMockDb() | 753 | cls.uninstallMockDb() |
1117 | 760 | 754 | ||
1118 | 761 | # Ensure that the database is connectable | 755 | # Ensure that the database is connectable |
1120 | 762 | DatabaseLayer.connect().close() | 756 | cls.connect().close() |
1121 | 763 | 757 | ||
1128 | 764 | # Imported here to avoid circular import issues. This | 758 | if cls._reset_between_tests: |
1129 | 765 | # functionality should be migrated into this module at some | 759 | cls._db_fixture.tearDown() |
1124 | 766 | # point. -- StuartBishop 20060712 | ||
1125 | 767 | from canonical.launchpad.ftests.harness import LaunchpadTestSetup | ||
1126 | 768 | if DatabaseLayer._reset_between_tests: | ||
1127 | 769 | LaunchpadTestSetup().tearDown() | ||
1130 | 770 | 760 | ||
1131 | 771 | # Fail tests that forget to uninstall their database policies. | 761 | # Fail tests that forget to uninstall their database policies. |
1132 | 772 | from canonical.launchpad.webapp.adapter import StoreSelector | 762 | from canonical.launchpad.webapp.adapter import StoreSelector |
1133 | @@ -781,7 +771,7 @@ | |||
1134 | 781 | @classmethod | 771 | @classmethod |
1135 | 782 | @profiled | 772 | @profiled |
1136 | 783 | def installMockDb(cls): | 773 | def installMockDb(cls): |
1138 | 784 | assert DatabaseLayer.mockdb_mode is None, 'mock db already installed' | 774 | assert cls.mockdb_mode is None, 'mock db already installed' |
1139 | 785 | 775 | ||
1140 | 786 | from canonical.testing.mockdb import ( | 776 | from canonical.testing.mockdb import ( |
1141 | 787 | script_filename, ScriptRecorder, ScriptPlayer, | 777 | script_filename, ScriptRecorder, ScriptPlayer, |
1142 | @@ -795,32 +785,32 @@ | |||
1143 | 795 | # mock db script. | 785 | # mock db script. |
1144 | 796 | filename = script_filename(test_key) | 786 | filename = script_filename(test_key) |
1145 | 797 | if os.path.exists(filename): | 787 | if os.path.exists(filename): |
1148 | 798 | DatabaseLayer.mockdb_mode = 'replay' | 788 | cls.mockdb_mode = 'replay' |
1149 | 799 | DatabaseLayer.script = ScriptPlayer(test_key) | 789 | cls.script = ScriptPlayer(test_key) |
1150 | 800 | else: | 790 | else: |
1153 | 801 | DatabaseLayer.mockdb_mode = 'record' | 791 | cls.mockdb_mode = 'record' |
1154 | 802 | DatabaseLayer.script = ScriptRecorder(test_key) | 792 | cls.script = ScriptRecorder(test_key) |
1155 | 803 | 793 | ||
1156 | 804 | global _org_connect | 794 | global _org_connect |
1157 | 805 | _org_connect = psycopg2.connect | 795 | _org_connect = psycopg2.connect |
1158 | 806 | # Proxy real connections with our mockdb. | 796 | # Proxy real connections with our mockdb. |
1159 | 807 | def fake_connect(*args, **kw): | 797 | def fake_connect(*args, **kw): |
1161 | 808 | return DatabaseLayer.script.connect(_org_connect, *args, **kw) | 798 | return cls.script.connect(_org_connect, *args, **kw) |
1162 | 809 | psycopg2.connect = fake_connect | 799 | psycopg2.connect = fake_connect |
1163 | 810 | 800 | ||
1164 | 811 | @classmethod | 801 | @classmethod |
1165 | 812 | @profiled | 802 | @profiled |
1166 | 813 | def uninstallMockDb(cls): | 803 | def uninstallMockDb(cls): |
1168 | 814 | if DatabaseLayer.mockdb_mode is None: | 804 | if cls.mockdb_mode is None: |
1169 | 815 | return # Already uninstalled | 805 | return # Already uninstalled |
1170 | 816 | 806 | ||
1171 | 817 | # Store results if we are recording | 807 | # Store results if we are recording |
1175 | 818 | if DatabaseLayer.mockdb_mode == 'record': | 808 | if cls.mockdb_mode == 'record': |
1176 | 819 | DatabaseLayer.script.store() | 809 | cls.script.store() |
1177 | 820 | assert os.path.exists(DatabaseLayer.script.script_filename), ( | 810 | assert os.path.exists(cls.script.script_filename), ( |
1178 | 821 | "Stored results but no script on disk.") | 811 | "Stored results but no script on disk.") |
1179 | 822 | 812 | ||
1181 | 823 | DatabaseLayer.mockdb_mode = None | 813 | cls.mockdb_mode = None |
1182 | 824 | global _org_connect | 814 | global _org_connect |
1183 | 825 | psycopg2.connect = _org_connect | 815 | psycopg2.connect = _org_connect |
1184 | 826 | _org_connect = None | 816 | _org_connect = None |
1185 | @@ -828,20 +818,17 @@ | |||
1186 | 828 | @classmethod | 818 | @classmethod |
1187 | 829 | @profiled | 819 | @profiled |
1188 | 830 | def force_dirty_database(cls): | 820 | def force_dirty_database(cls): |
1191 | 831 | from canonical.launchpad.ftests.harness import LaunchpadTestSetup | 821 | cls._db_fixture.force_dirty_database() |
1190 | 832 | LaunchpadTestSetup().force_dirty_database() | ||
1192 | 833 | 822 | ||
1193 | 834 | @classmethod | 823 | @classmethod |
1194 | 835 | @profiled | 824 | @profiled |
1195 | 836 | def connect(cls): | 825 | def connect(cls): |
1198 | 837 | from canonical.launchpad.ftests.harness import LaunchpadTestSetup | 826 | return cls._db_fixture.connect() |
1197 | 838 | return LaunchpadTestSetup().connect() | ||
1199 | 839 | 827 | ||
1200 | 840 | @classmethod | 828 | @classmethod |
1201 | 841 | @profiled | 829 | @profiled |
1202 | 842 | def _dropDb(cls): | 830 | def _dropDb(cls): |
1205 | 843 | from canonical.launchpad.ftests.harness import LaunchpadTestSetup | 831 | return cls._db_fixture.dropDb() |
1204 | 844 | return LaunchpadTestSetup().dropDb() | ||
1206 | 845 | 832 | ||
1207 | 846 | 833 | ||
1208 | 847 | def test_default_timeout(): | 834 | def test_default_timeout(): |
1209 | @@ -1378,6 +1365,11 @@ | |||
1210 | 1378 | reconnect_stores(database_config_section=database_config_section) | 1365 | reconnect_stores(database_config_section=database_config_section) |
1211 | 1379 | 1366 | ||
1212 | 1380 | 1367 | ||
1213 | 1368 | class LaunchpadTestSetup(PgTestSetup): | ||
1214 | 1369 | template = 'launchpad_ftest_template' | ||
1215 | 1370 | dbuser = 'launchpad' | ||
1216 | 1371 | |||
1217 | 1372 | |||
1218 | 1381 | class LaunchpadZopelessLayer(LaunchpadScriptLayer): | 1373 | class LaunchpadZopelessLayer(LaunchpadScriptLayer): |
1219 | 1382 | """Full Zopeless environment including Component Architecture and | 1374 | """Full Zopeless environment including Component Architecture and |
1220 | 1383 | database connections initialized. | 1375 | database connections initialized. |
1221 | @@ -1643,6 +1635,9 @@ | |||
1222 | 1643 | # configs/testrunner-appserver/mail-configure.zcml | 1635 | # configs/testrunner-appserver/mail-configure.zcml |
1223 | 1644 | smtp_controller = None | 1636 | smtp_controller = None |
1224 | 1645 | 1637 | ||
1225 | 1638 | # The DB fixture in use | ||
1226 | 1639 | _db_fixture = None | ||
1227 | 1640 | |||
1228 | 1646 | @classmethod | 1641 | @classmethod |
1229 | 1647 | @profiled | 1642 | @profiled |
1230 | 1648 | def startSMTPServer(cls): | 1643 | def startSMTPServer(cls): |
1231 | @@ -1770,9 +1765,12 @@ | |||
1232 | 1770 | @classmethod | 1765 | @classmethod |
1233 | 1771 | def _runAppServer(cls): | 1766 | def _runAppServer(cls): |
1234 | 1772 | """Start the app server using runlaunchpad.py""" | 1767 | """Start the app server using runlaunchpad.py""" |
1235 | 1773 | from canonical.launchpad.ftests.harness import LaunchpadTestSetup | ||
1236 | 1774 | # The database must be available for the app server to start. | 1768 | # The database must be available for the app server to start. |
1238 | 1775 | LaunchpadTestSetup().setUp() | 1769 | cls._db_fixture = LaunchpadTestSetup() |
1239 | 1770 | # This is not torn down properly: rather the singleton nature is abused | ||
1240 | 1771 | # and the fixture is simply marked as being dirty. | ||
1241 | 1772 | # XXX: Robert Collins 2010-10-17 bug=661967 | ||
1242 | 1773 | cls._db_fixture.setUp() | ||
1243 | 1776 | # The app server will not start at all if the database hasn't been | 1774 | # The app server will not start at all if the database hasn't been |
1244 | 1777 | # correctly patched. The app server will make exactly this check, | 1775 | # correctly patched. The app server will make exactly this check, |
1245 | 1778 | # doing it here makes the error more obvious. | 1776 | # doing it here makes the error more obvious. |
1246 | 1779 | 1777 | ||
1247 | === modified file 'lib/lp/codehosting/tests/test_acceptance.py' | |||
1248 | --- lib/lp/codehosting/tests/test_acceptance.py 2010-10-04 19:50:45 +0000 | |||
1249 | +++ lib/lp/codehosting/tests/test_acceptance.py 2010-10-17 19:12:52 +0000 | |||
1250 | @@ -21,7 +21,6 @@ | |||
1251 | 21 | from zope.component import getUtility | 21 | from zope.component import getUtility |
1252 | 22 | 22 | ||
1253 | 23 | from canonical.config import config | 23 | from canonical.config import config |
1254 | 24 | from canonical.launchpad.ftests.harness import LaunchpadZopelessTestSetup | ||
1255 | 25 | from canonical.testing.layers import ZopelessAppServerLayer | 24 | from canonical.testing.layers import ZopelessAppServerLayer |
1256 | 26 | from canonical.testing.profiled import profiled | 25 | from canonical.testing.profiled import profiled |
1257 | 27 | from lp.code.bzr import ( | 26 | from lp.code.bzr import ( |
1258 | @@ -334,7 +333,7 @@ | |||
1259 | 334 | remote_url = self.getTransportURL('~testuser/+junk/test-branch') | 333 | remote_url = self.getTransportURL('~testuser/+junk/test-branch') |
1260 | 335 | self.push(self.local_branch_path, remote_url) | 334 | self.push(self.local_branch_path, remote_url) |
1261 | 336 | self.assertBranchesMatch(self.local_branch_path, remote_url) | 335 | self.assertBranchesMatch(self.local_branch_path, remote_url) |
1263 | 337 | LaunchpadZopelessTestSetup().txn.begin() | 336 | ZopelessAppServerLayer.txn.begin() |
1264 | 338 | db_branch = getUtility(IBranchSet).getByUniqueName( | 337 | db_branch = getUtility(IBranchSet).getByUniqueName( |
1265 | 339 | '~testuser/+junk/test-branch') | 338 | '~testuser/+junk/test-branch') |
1266 | 340 | self.assertEqual( | 339 | self.assertEqual( |
1267 | @@ -343,7 +342,7 @@ | |||
1268 | 343 | BranchFormat.BZR_BRANCH_7, db_branch.branch_format) | 342 | BranchFormat.BZR_BRANCH_7, db_branch.branch_format) |
1269 | 344 | self.assertEqual( | 343 | self.assertEqual( |
1270 | 345 | ControlFormat.BZR_METADIR_1, db_branch.control_format) | 344 | ControlFormat.BZR_METADIR_1, db_branch.control_format) |
1272 | 346 | LaunchpadZopelessTestSetup().txn.commit() | 345 | ZopelessAppServerLayer.txn.commit() |
1273 | 347 | 346 | ||
1274 | 348 | def test_push_to_existing_branch(self): | 347 | def test_push_to_existing_branch(self): |
1275 | 349 | """Pushing to an existing branch must work.""" | 348 | """Pushing to an existing branch must work.""" |
1276 | @@ -374,12 +373,12 @@ | |||
1277 | 374 | self.push(self.local_branch_path, remote_url) | 373 | self.push(self.local_branch_path, remote_url) |
1278 | 375 | 374 | ||
1279 | 376 | # Rename owner, product and branch in the database | 375 | # Rename owner, product and branch in the database |
1281 | 377 | LaunchpadZopelessTestSetup().txn.begin() | 376 | ZopelessAppServerLayer.txn.begin() |
1282 | 378 | branch = self.getDatabaseBranch('testuser', None, 'test-branch') | 377 | branch = self.getDatabaseBranch('testuser', None, 'test-branch') |
1283 | 379 | branch.owner.name = 'renamed-user' | 378 | branch.owner.name = 'renamed-user' |
1284 | 380 | branch.setTarget(user=branch.owner, project=Product.byName('firefox')) | 379 | branch.setTarget(user=branch.owner, project=Product.byName('firefox')) |
1285 | 381 | branch.name = 'renamed-branch' | 380 | branch.name = 'renamed-branch' |
1287 | 382 | LaunchpadZopelessTestSetup().txn.commit() | 381 | ZopelessAppServerLayer.txn.commit() |
1288 | 383 | 382 | ||
1289 | 384 | # Check that it's not at the old location. | 383 | # Check that it's not at the old location. |
1290 | 385 | self.assertNotBranch( | 384 | self.assertNotBranch( |
1291 | @@ -405,23 +404,23 @@ | |||
1292 | 405 | '~testuser/+junk/totally-new-branch') | 404 | '~testuser/+junk/totally-new-branch') |
1293 | 406 | self.push(self.local_branch_path, remote_url) | 405 | self.push(self.local_branch_path, remote_url) |
1294 | 407 | 406 | ||
1296 | 408 | LaunchpadZopelessTestSetup().txn.begin() | 407 | ZopelessAppServerLayer.txn.begin() |
1297 | 409 | branch = self.getDatabaseBranch( | 408 | branch = self.getDatabaseBranch( |
1298 | 410 | 'testuser', None, 'totally-new-branch') | 409 | 'testuser', None, 'totally-new-branch') |
1299 | 411 | 410 | ||
1300 | 412 | self.assertEqual( | 411 | self.assertEqual( |
1301 | 413 | ['~testuser/+junk/totally-new-branch', self.revid], | 412 | ['~testuser/+junk/totally-new-branch', self.revid], |
1302 | 414 | [branch.unique_name, branch.last_mirrored_id]) | 413 | [branch.unique_name, branch.last_mirrored_id]) |
1304 | 415 | LaunchpadZopelessTestSetup().txn.abort() | 414 | ZopelessAppServerLayer.txn.abort() |
1305 | 416 | 415 | ||
1306 | 417 | def test_record_default_stacking(self): | 416 | def test_record_default_stacking(self): |
1307 | 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, |
1308 | 419 | # then branches pushed to that location end up stacked on it by | 418 | # then branches pushed to that location end up stacked on it by |
1309 | 420 | # default. | 419 | # default. |
1310 | 421 | product = self.factory.makeProduct() | 420 | product = self.factory.makeProduct() |
1312 | 422 | LaunchpadZopelessTestSetup().txn.commit() | 421 | ZopelessAppServerLayer.txn.commit() |
1313 | 423 | 422 | ||
1315 | 424 | LaunchpadZopelessTestSetup().txn.begin() | 423 | ZopelessAppServerLayer.txn.begin() |
1316 | 425 | 424 | ||
1317 | 426 | self.make_branch_and_tree('stacked-on') | 425 | self.make_branch_and_tree('stacked-on') |
1318 | 427 | trunk_unique_name = '~testuser/%s/trunk' % product.name | 426 | trunk_unique_name = '~testuser/%s/trunk' % product.name |
1319 | @@ -431,7 +430,7 @@ | |||
1320 | 431 | self.factory.enableDefaultStackingForProduct( | 430 | self.factory.enableDefaultStackingForProduct( |
1321 | 432 | db_trunk.product, db_trunk) | 431 | db_trunk.product, db_trunk) |
1322 | 433 | 432 | ||
1324 | 434 | LaunchpadZopelessTestSetup().txn.commit() | 433 | ZopelessAppServerLayer.txn.commit() |
1325 | 435 | 434 | ||
1326 | 436 | stacked_unique_name = '~testuser/%s/stacked' % product.name | 435 | stacked_unique_name = '~testuser/%s/stacked' % product.name |
1327 | 437 | self.push( | 436 | self.push( |
1328 | @@ -447,7 +446,7 @@ | |||
1329 | 447 | # attribute of the database branch, and stacked on location of the new | 446 | # attribute of the database branch, and stacked on location of the new |
1330 | 448 | # branch is normalized to be a relative path. | 447 | # branch is normalized to be a relative path. |
1331 | 449 | product = self.factory.makeProduct() | 448 | product = self.factory.makeProduct() |
1333 | 450 | LaunchpadZopelessTestSetup().txn.commit() | 449 | ZopelessAppServerLayer.txn.commit() |
1334 | 451 | 450 | ||
1335 | 452 | self.make_branch_and_tree('stacked-on') | 451 | self.make_branch_and_tree('stacked-on') |
1336 | 453 | trunk_unique_name = '~testuser/%s/trunk' % product.name | 452 | trunk_unique_name = '~testuser/%s/trunk' % product.name |
1337 | @@ -507,11 +506,11 @@ | |||
1338 | 507 | def test_push_to_new_short_branch_alias(self): | 506 | def test_push_to_new_short_branch_alias(self): |
1339 | 508 | # We can also push branches to URLs like /+branch/firefox | 507 | # We can also push branches to URLs like /+branch/firefox |
1340 | 509 | # Hack 'firefox' so we have permission to do this. | 508 | # Hack 'firefox' so we have permission to do this. |
1342 | 510 | LaunchpadZopelessTestSetup().txn.begin() | 509 | ZopelessAppServerLayer.txn.begin() |
1343 | 511 | firefox = Product.selectOneBy(name='firefox') | 510 | firefox = Product.selectOneBy(name='firefox') |
1344 | 512 | testuser = Person.selectOneBy(name='testuser') | 511 | testuser = Person.selectOneBy(name='testuser') |
1345 | 513 | firefox.development_focus.owner = testuser | 512 | firefox.development_focus.owner = testuser |
1347 | 514 | LaunchpadZopelessTestSetup().txn.commit() | 513 | ZopelessAppServerLayer.txn.commit() |
1348 | 515 | remote_url = self.getTransportURL('+branch/firefox') | 514 | remote_url = self.getTransportURL('+branch/firefox') |
1349 | 516 | self.push(self.local_branch_path, remote_url) | 515 | self.push(self.local_branch_path, remote_url) |
1350 | 517 | self.assertBranchesMatch(self.local_branch_path, remote_url) | 516 | self.assertBranchesMatch(self.local_branch_path, remote_url) |
1351 | @@ -520,10 +519,10 @@ | |||
1352 | 520 | # If a hosted branch exists in the database, but not on the | 519 | # If a hosted branch exists in the database, but not on the |
1353 | 521 | # filesystem, and is writable by the user, then the user is able to | 520 | # filesystem, and is writable by the user, then the user is able to |
1354 | 522 | # push to it. | 521 | # push to it. |
1356 | 523 | LaunchpadZopelessTestSetup().txn.begin() | 522 | ZopelessAppServerLayer.txn.begin() |
1357 | 524 | branch = self.makeDatabaseBranch('testuser', 'firefox', 'some-branch') | 523 | branch = self.makeDatabaseBranch('testuser', 'firefox', 'some-branch') |
1358 | 525 | remote_url = self.getTransportURL(branch.unique_name) | 524 | remote_url = self.getTransportURL(branch.unique_name) |
1360 | 526 | LaunchpadZopelessTestSetup().txn.commit() | 525 | ZopelessAppServerLayer.txn.commit() |
1361 | 527 | self.push( | 526 | self.push( |
1362 | 528 | self.local_branch_path, remote_url, | 527 | self.local_branch_path, remote_url, |
1363 | 529 | extra_args=['--use-existing-dir']) | 528 | extra_args=['--use-existing-dir']) |
1364 | @@ -531,21 +530,21 @@ | |||
1365 | 531 | 530 | ||
1366 | 532 | def test_cant_push_to_existing_mirrored_branch(self): | 531 | def test_cant_push_to_existing_mirrored_branch(self): |
1367 | 533 | # Users cannot push to mirrored branches. | 532 | # Users cannot push to mirrored branches. |
1369 | 534 | LaunchpadZopelessTestSetup().txn.begin() | 533 | ZopelessAppServerLayer.txn.begin() |
1370 | 535 | branch = self.makeDatabaseBranch( | 534 | branch = self.makeDatabaseBranch( |
1371 | 536 | 'testuser', 'firefox', 'some-branch', BranchType.MIRRORED) | 535 | 'testuser', 'firefox', 'some-branch', BranchType.MIRRORED) |
1372 | 537 | remote_url = self.getTransportURL(branch.unique_name) | 536 | remote_url = self.getTransportURL(branch.unique_name) |
1374 | 538 | LaunchpadZopelessTestSetup().txn.commit() | 537 | ZopelessAppServerLayer.txn.commit() |
1375 | 539 | self.assertCantPush( | 538 | self.assertCantPush( |
1376 | 540 | self.local_branch_path, remote_url, | 539 | self.local_branch_path, remote_url, |
1377 | 541 | ['Permission denied:', 'Transport operation not possible:']) | 540 | ['Permission denied:', 'Transport operation not possible:']) |
1378 | 542 | 541 | ||
1379 | 543 | def test_cant_push_to_existing_unowned_hosted_branch(self): | 542 | def test_cant_push_to_existing_unowned_hosted_branch(self): |
1380 | 544 | # Users can only push to hosted branches that they own. | 543 | # Users can only push to hosted branches that they own. |
1382 | 545 | LaunchpadZopelessTestSetup().txn.begin() | 544 | ZopelessAppServerLayer.txn.begin() |
1383 | 546 | branch = self.makeDatabaseBranch('mark', 'firefox', 'some-branch') | 545 | branch = self.makeDatabaseBranch('mark', 'firefox', 'some-branch') |
1384 | 547 | remote_url = self.getTransportURL(branch.unique_name) | 546 | remote_url = self.getTransportURL(branch.unique_name) |
1386 | 548 | LaunchpadZopelessTestSetup().txn.commit() | 547 | ZopelessAppServerLayer.txn.commit() |
1387 | 549 | self.assertCantPush( | 548 | self.assertCantPush( |
1388 | 550 | self.local_branch_path, remote_url, | 549 | self.local_branch_path, remote_url, |
1389 | 551 | ['Permission denied:', 'Transport operation not possible:']) | 550 | ['Permission denied:', 'Transport operation not possible:']) |
1390 | @@ -566,12 +565,12 @@ | |||
1391 | 566 | person_name, product_name, branch_name) | 565 | person_name, product_name, branch_name) |
1392 | 567 | 566 | ||
1393 | 568 | # Mark as mirrored. | 567 | # Mark as mirrored. |
1395 | 569 | LaunchpadZopelessTestSetup().txn.begin() | 568 | ZopelessAppServerLayer.txn.begin() |
1396 | 570 | branch = self.getDatabaseBranch( | 569 | branch = self.getDatabaseBranch( |
1397 | 571 | person_name, product_name, branch_name) | 570 | person_name, product_name, branch_name) |
1398 | 572 | branch.branch_type = BranchType.MIRRORED | 571 | branch.branch_type = BranchType.MIRRORED |
1399 | 573 | branch.url = "http://example.com/smartservertest/branch" | 572 | branch.url = "http://example.com/smartservertest/branch" |
1401 | 574 | LaunchpadZopelessTestSetup().txn.commit() | 573 | ZopelessAppServerLayer.txn.commit() |
1402 | 575 | return ro_branch_url | 574 | return ro_branch_url |
1403 | 576 | 575 | ||
1404 | 577 | def test_can_read_readonly_branch(self): | 576 | def test_can_read_readonly_branch(self): |
1405 | 578 | 577 | ||
1406 | === modified file 'lib/lp/soyuz/doc/sampledata-setup.txt' | |||
1407 | --- lib/lp/soyuz/doc/sampledata-setup.txt 2010-08-13 02:59:14 +0000 | |||
1408 | +++ lib/lp/soyuz/doc/sampledata-setup.txt 2010-10-17 19:12:52 +0000 | |||
1409 | @@ -21,5 +21,5 @@ | |||
1410 | 21 | INFO ... | 21 | INFO ... |
1411 | 22 | INFO Done. | 22 | INFO Done. |
1412 | 23 | 23 | ||
1415 | 24 | >>> from canonical.launchpad.ftests.harness import LaunchpadTestSetup | 24 | >>> from canonical.testing.layers import DatabaseLayer |
1416 | 25 | >>> LaunchpadTestSetup().force_dirty_database() | 25 | >>> DatabaseLayer.force_dirty_database() |
1417 | 26 | 26 | ||
1418 | === modified file 'lib/lp/soyuz/scripts/tests/test_buildd_cronscripts.py' | |||
1419 | --- lib/lp/soyuz/scripts/tests/test_buildd_cronscripts.py 2010-10-04 19:50:45 +0000 | |||
1420 | +++ lib/lp/soyuz/scripts/tests/test_buildd_cronscripts.py 2010-10-17 19:12:52 +0000 | |||
1421 | @@ -74,9 +74,8 @@ | |||
1422 | 74 | rc, out, err = runner() | 74 | rc, out, err = runner() |
1423 | 75 | self.assertEqual(0, rc, "Err:\n%s" % err) | 75 | self.assertEqual(0, rc, "Err:\n%s" % err) |
1424 | 76 | 76 | ||
1428 | 77 | # 'runners' commit to the launchpad_ftest database in | 77 | # 'runners' commit to the test database in subprocesses, so we need to |
1429 | 78 | # subprocesses, so we need to tell the layer to fully | 78 | # tell the layer to fully tear down and restore the database. |
1427 | 79 | # tear down and restore the database. | ||
1430 | 80 | DatabaseLayer.force_dirty_database() | 79 | DatabaseLayer.force_dirty_database() |
1431 | 81 | 80 | ||
1432 | 82 | return rc, out, err | 81 | return rc, out, err |
1433 | 83 | 82 | ||
1434 | === modified file 'lib/lp/translations/doc/fix_translation_credits.txt' | |||
1435 | --- lib/lp/translations/doc/fix_translation_credits.txt 2010-04-01 04:05:10 +0000 | |||
1436 | +++ lib/lp/translations/doc/fix_translation_credits.txt 2010-10-17 19:12:52 +0000 | |||
1437 | @@ -19,5 +19,5 @@ | |||
1438 | 19 | After altering the database from a separate process, we must tell the | 19 | After altering the database from a separate process, we must tell the |
1439 | 20 | test setup that the database is dirty in spite of appearances. | 20 | test setup that the database is dirty in spite of appearances. |
1440 | 21 | 21 | ||
1443 | 22 | >>> from canonical.launchpad.ftests.harness import LaunchpadTestSetup | 22 | >>> from canonical.testing.layers import DatabaseLayer |
1444 | 23 | >>> LaunchpadTestSetup().force_dirty_database() | 23 | >>> DatabaseLayer.force_dirty_database() |
1445 | 24 | 24 | ||
1446 | === modified file 'lib/lp/translations/doc/message-sharing-merge-script.txt' | |||
1447 | --- lib/lp/translations/doc/message-sharing-merge-script.txt 2009-08-04 13:37:57 +0000 | |||
1448 | +++ lib/lp/translations/doc/message-sharing-merge-script.txt 2010-10-17 19:12:52 +0000 | |||
1449 | @@ -20,5 +20,5 @@ | |||
1450 | 20 | # The script modified the database, even though the database layer may | 20 | # The script modified the database, even though the database layer may |
1451 | 21 | # not have noticed it. | 21 | # not have noticed it. |
1452 | 22 | 22 | ||
1455 | 23 | >>> from canonical.launchpad.ftests.harness import LaunchpadTestSetup | 23 | >>> from canonical.testing.layers import DatabaseLayer |
1456 | 24 | >>> LaunchpadTestSetup().force_dirty_database() | 24 | >>> DatabaseLayer.force_dirty_database() |
1457 | 25 | 25 | ||
1458 | === modified file 'lib/lp/translations/doc/request_country.txt' | |||
1459 | --- lib/lp/translations/doc/request_country.txt 2010-02-26 21:58:15 +0000 | |||
1460 | +++ lib/lp/translations/doc/request_country.txt 2010-10-17 19:12:52 +0000 | |||
1461 | @@ -4,10 +4,6 @@ | |||
1462 | 4 | 4 | ||
1463 | 5 | Adapting a request to a country allows you to see where the request came from. | 5 | Adapting a request to a country allows you to see where the request came from. |
1464 | 6 | 6 | ||
1465 | 7 | >>> from canonical.launchpad.ftests.harness import ( | ||
1466 | 8 | ... LaunchpadFunctionalTestSetup) | ||
1467 | 9 | >>> LaunchpadFunctionalTestSetup().setUp() | ||
1468 | 10 | |||
1469 | 11 | Here's a dummy request. Zope adds the REMOTE_ADDR CGI environment variable | 7 | Here's a dummy request. Zope adds the REMOTE_ADDR CGI environment variable |
1470 | 12 | for us. Upstream proxy servers (and tinkering users!) may also add | 8 | for us. Upstream proxy servers (and tinkering users!) may also add |
1471 | 13 | X-Forwarded-For: headers. The X-Forwarded-For: header takes precidence | 9 | X-Forwarded-For: headers. The X-Forwarded-For: header takes precidence |
1472 | @@ -34,6 +30,3 @@ | |||
1473 | 34 | Traceback (most recent call last): | 30 | Traceback (most recent call last): |
1474 | 35 | ... | 31 | ... |
1475 | 36 | TypeError: ('Could not adapt', ... | 32 | TypeError: ('Could not adapt', ... |
1476 | 37 | |||
1477 | 38 | >>> LaunchpadFunctionalTestSetup().tearDown() | ||
1478 | 39 |
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