Merge lp:~wgrant/launchpad/secret-query-count-determinism into lp:launchpad

Proposed by William Grant
Status: Merged
Approved by: Jonathan Lange
Approved revision: no longer in the source branch.
Merged at revision: 12461
Proposed branch: lp:~wgrant/launchpad/secret-query-count-determinism
Merge into: lp:launchpad
Diff against target: 66 lines (+12/-8)
3 files modified
lib/canonical/testing/layers.py (+4/-0)
lib/devscripts/ec2test/remote.py (+7/-7)
lib/lp/bugs/scripts/checkwatches/remotebugupdater.py (+1/-1)
To merge this branch: bzr merge lp:~wgrant/launchpad/secret-query-count-determinism
Reviewer Review Type Date Requested Status
Jonathan Lange (community) Approve
Review via email: mp+51086@code.launchpad.net

Commit message

[r=jml][bug=724039,724232][no-qa] Prepopulate the cookie secret cache, preventing tests from seeing an extra query when they are the first in a layer.

Description of the change

This branch fixes a spurious failure that I sort of introduced in r12418.

LaunchpadCookieIdClientManager.secret is a manually cached property that is not cleared across transactions -- its state can leak between tests. This means that the first test in a layer can see an extra query as that cache is populated, causing query count to fluctuate depending on test order. Most tests already have a safety buffer of one query, so they tolerate this fluctuation.

r12418 caused transaction lifecycle events to be logged, adding an extra 'query' to most browser requests. This pushed some tests over their limit, but only when run as the first test in a layer. This branch causes the secret cache to be populated at layer setup time, removing the state leak and making query counts static again.

To see the difference, try these two test runs:

 bin/test -cvvvt test_binary_query_counts -t test_source_query_counts
 bin/test -cvvvt test_source_query_counts

The first invocation should always succeed, while the latter will fail without this branch.

I also fixed an unrelated import that was causing the import fascist to whinge.

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

Personally, I'd prefer you didn't assign to 'unused', since that makes pyflakes upset. But that's a personal thing.

I also wish there were a better solution.

Either way, good to land.

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

Looks good. Thanks for making pyflakes happy.

I wish the plugins change could be tested – I went to some effort to give remote.py good coverage – but I'm not sure how, or whether it would be an effective use of code. The right way to test it would be to check that it unpickled whatever it was that needs unpickling when run in a sub-process (so as to avoid the loaded plugins of the test process).

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/canonical/testing/layers.py'
--- lib/canonical/testing/layers.py 2011-02-19 13:50:19 +0000
+++ lib/canonical/testing/layers.py 2011-02-24 14:03:54 +0000
@@ -95,6 +95,7 @@
95from zope.server.logger.pythonlogger import PythonLogger95from zope.server.logger.pythonlogger import PythonLogger
96from zope.testing.testrunner.runner import FakeInputContinueGenerator96from zope.testing.testrunner.runner import FakeInputContinueGenerator
9797
98import canonical.launchpad.webapp.session
98from canonical.launchpad.webapp.vhosts import allvhosts99from canonical.launchpad.webapp.vhosts import allvhosts
99from canonical.lazr import pidfile100from canonical.lazr import pidfile
100from canonical.config import CanonicalConfig, config, dbconfig101from canonical.config import CanonicalConfig, config, dbconfig
@@ -1054,6 +1055,9 @@
1054 if not is_ca_available():1055 if not is_ca_available():
1055 raise LayerInvariantError("Component architecture failed to load")1056 raise LayerInvariantError("Component architecture failed to load")
10561057
1058 # Access the cookie manager's secret to get the cache populated.
1059 # If we don't, it may issue extra queries depending on test order.
1060 canonical.launchpad.webapp.session.idmanager.secret
1057 # If our request publication factories were defined using ZCML,1061 # If our request publication factories were defined using ZCML,
1058 # they'd be set up by FunctionalTestSetup().setUp(). Since1062 # they'd be set up by FunctionalTestSetup().setUp(). Since
1059 # they're defined by Python code, we need to call that code1063 # they're defined by Python code, we need to call that code
10601064
=== modified file 'lib/devscripts/ec2test/remote.py'
--- lib/devscripts/ec2test/remote.py 2011-02-23 11:41:12 +0000
+++ lib/devscripts/ec2test/remote.py 2011-02-24 14:03:54 +0000
@@ -36,20 +36,20 @@
36import unittest36import unittest
37from xml.sax.saxutils import escape37from xml.sax.saxutils import escape
3838
39import simplejson
40
41import bzrlib.branch39import bzrlib.branch
42import bzrlib.config40import bzrlib.config
41from bzrlib.email_message import EmailMessage
43import bzrlib.errors42import bzrlib.errors
43from bzrlib.smtp_connection import SMTPConnection
44import bzrlib.workingtree44import bzrlib.workingtree
4545import simplejson
46from bzrlib.email_message import EmailMessage
47from bzrlib.smtp_connection import SMTPConnection
48
49import subunit46import subunit
50
51from testtools import MultiTestResult47from testtools import MultiTestResult
5248
49# We need to be able to unpickle objects from bzr-pqm, so make sure we
50# can import it.
51bzrlib.plugin.load_plugins()
52
5353
54class NonZeroExitCode(Exception):54class NonZeroExitCode(Exception):
55 """Raised when the child process exits with a non-zero exit code."""55 """Raised when the child process exits with a non-zero exit code."""
5656
=== modified file 'lib/lp/bugs/scripts/checkwatches/remotebugupdater.py'
--- lib/lp/bugs/scripts/checkwatches/remotebugupdater.py 2011-02-23 08:57:39 +0000
+++ lib/lp/bugs/scripts/checkwatches/remotebugupdater.py 2011-02-24 14:03:54 +0000
@@ -13,7 +13,7 @@
13from zope.component import getUtility13from zope.component import getUtility
1414
15from canonical.database.constants import UTC_NOW15from canonical.database.constants import UTC_NOW
16from lp.bugs.externalbugtracker import (16from lp.bugs.externalbugtracker.base import (
17 BugNotFound,17 BugNotFound,
18 InvalidBugId,18 InvalidBugId,
19 PrivateRemoteBug,19 PrivateRemoteBug,