Merge lp:~stub/launchpad/pgbouncer-fixture-noca into lp:launchpad

Proposed by Stuart Bishop
Status: Merged
Approved by: Stuart Bishop
Approved revision: no longer in the source branch.
Merged at revision: 13863
Proposed branch: lp:~stub/launchpad/pgbouncer-fixture-noca
Merge into: lp:launchpad
Prerequisite: lp:~stub/launchpad/pgbouncer-fixture
Diff against target: 126 lines (+74/-5)
2 files modified
lib/lp/testing/fixture.py (+16/-3)
lib/lp/testing/tests/test_fixture.py (+58/-2)
To merge this branch: bzr merge lp:~stub/launchpad/pgbouncer-fixture-noca
Reviewer Review Type Date Requested Status
Gavin Panella (community) Approve
Review via email: mp+73525@code.launchpad.net

Commit message

[r=jtv,allenap][no-qa] pgbouncer test fixture allowing tests of database disconnection behavior.

Description of the change

= Summary =

PGBouncerFixture would not work in layers without the Component Architecture loaded, such as DatabaseLayer, because it would attempt to reset the Storm Stores and these were not registered.

== Proposed fix ==

Only reset the Storm Stores if they are registered with the Component Architecture.

To post a comment you must log in.
Revision history for this message
Gavin Panella (allenap) wrote :

Looks good.

[1]

You might find assertTrue to be a prettier synonym for assert_
(alternatively, both are synonyms for failUnless).

[2]

+ def is_db_available(self):

Could this method be useful elsewhere? If so, the effort to extract it
into a matcher might be worth it.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/testing/fixture.py'
--- lib/lp/testing/fixture.py 2011-09-03 02:27:01 +0000
+++ lib/lp/testing/fixture.py 2011-09-03 02:27:03 +0000
@@ -91,8 +91,7 @@
9191
92 # reconnect_store cleanup added first so it is run last, after92 # reconnect_store cleanup added first so it is run last, after
93 # the environment variables have been reset.93 # the environment variables have been reset.
94 from canonical.testing.layers import reconnect_stores94 self.addCleanup(self._maybe_reconnect_stores)
95 self.addCleanup(reconnect_stores)
9695
97 # Abuse the PGPORT environment variable to get things connecting96 # Abuse the PGPORT environment variable to get things connecting
98 # via pgbouncer. Otherwise, we would need to temporarily97 # via pgbouncer. Otherwise, we would need to temporarily
@@ -100,7 +99,21 @@
100 self.useFixture(EnvironmentVariableFixture('PGPORT', str(self.port)))99 self.useFixture(EnvironmentVariableFixture('PGPORT', str(self.port)))
101100
102 # Reset database connections so they go through pgbouncer.101 # Reset database connections so they go through pgbouncer.
103 reconnect_stores()102 self._maybe_reconnect_stores()
103
104 def _maybe_reconnect_stores(self):
105 """Force Storm Stores to reconnect if they are registered.
106
107 This is a noop if the Component Architecture is not loaded,
108 as we are using a test layer that doesn't provide database
109 connections.
110 """
111 from canonical.testing.layers import (
112 reconnect_stores,
113 is_ca_available,
114 )
115 if is_ca_available():
116 reconnect_stores()
104117
105118
106class ZopeAdapterFixture(Fixture):119class ZopeAdapterFixture(Fixture):
107120
=== modified file 'lib/lp/testing/tests/test_fixture.py'
--- lib/lp/testing/tests/test_fixture.py 2011-09-03 02:27:01 +0000
+++ lib/lp/testing/tests/test_fixture.py 2011-09-03 02:27:03 +0000
@@ -8,6 +8,7 @@
8from textwrap import dedent8from textwrap import dedent
99
10from fixtures import EnvironmentVariableFixture10from fixtures import EnvironmentVariableFixture
11import psycopg2
11from storm.exceptions import DisconnectionError12from storm.exceptions import DisconnectionError
12from zope.component import (13from zope.component import (
13 adapts,14 adapts,
@@ -18,8 +19,13 @@
18 Interface,19 Interface,
19 )20 )
2021
22from canonical.config import dbconfig
21from canonical.launchpad.interfaces.lpstorm import IMasterStore23from canonical.launchpad.interfaces.lpstorm import IMasterStore
22from canonical.testing.layers import BaseLayer, LaunchpadZopelessLayer24from canonical.testing.layers import (
25 BaseLayer,
26 DatabaseLayer,
27 LaunchpadZopelessLayer,
28 )
23from lp.registry.model.person import Person29from lp.registry.model.person import Person
24from lp.testing import TestCase30from lp.testing import TestCase
25from lp.testing.fixture import (31from lp.testing.fixture import (
@@ -95,7 +101,11 @@
95 self.assertIs(None, queryAdapter(context, IBar))101 self.assertIs(None, queryAdapter(context, IBar))
96102
97103
98class TestPGBouncerFixture(TestCase):104class TestPGBouncerFixtureWithCA(TestCase):
105 """PGBouncerFixture reconnect tests for Component Architecture layers.
106
107 Registered Storm Stores should be reconnected through pgbouncer.
108 """
99 layer = LaunchpadZopelessLayer109 layer = LaunchpadZopelessLayer
100110
101 def is_connected(self):111 def is_connected(self):
@@ -149,3 +159,49 @@
149159
150 # Database is working again.160 # Database is working again.
151 assert self.is_connected()161 assert self.is_connected()
162
163
164class TestPGBouncerFixtureWithoutCA(TestCase):
165 """PGBouncerFixture tests for non-Component Architecture layers."""
166 layer = DatabaseLayer
167
168 def is_db_available(self):
169 # Direct connection to the DB.
170 con_str = dbconfig.rw_main_master + ' user=launchpad_main'
171 try:
172 con = psycopg2.connect(con_str)
173 cur = con.cursor()
174 cur.execute("SELECT id FROM Person LIMIT 1")
175 con.close()
176 return True
177 except psycopg2.OperationalError:
178 return False
179
180 def test_install_fixture(self):
181 self.assert_(self.is_db_available())
182
183 with PGBouncerFixture() as pgbouncer:
184 self.assertTrue(self.is_db_available())
185
186 pgbouncer.stop()
187 self.assertFalse(self.is_db_available())
188
189 # This confirms that we are again connecting directly to the
190 # database, as the pgbouncer process was shutdown.
191 self.assertTrue(self.is_db_available())
192
193 def test_install_fixture_with_restart(self):
194 self.assert_(self.is_db_available())
195
196 with PGBouncerFixture() as pgbouncer:
197 self.assertTrue(self.is_db_available())
198
199 pgbouncer.stop()
200 self.assertFalse(self.is_db_available())
201
202 pgbouncer.start()
203 self.assertTrue(self.is_db_available())
204
205 # Note that because pgbouncer was left running, we can't confirm
206 # that we are now connecting directly to the database.
207 self.assertTrue(self.is_db_available())