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
1=== modified file 'lib/canonical/testing/layers.py'
2--- lib/canonical/testing/layers.py 2011-02-19 13:50:19 +0000
3+++ lib/canonical/testing/layers.py 2011-02-24 14:03:54 +0000
4@@ -95,6 +95,7 @@
5 from zope.server.logger.pythonlogger import PythonLogger
6 from zope.testing.testrunner.runner import FakeInputContinueGenerator
7
8+import canonical.launchpad.webapp.session
9 from canonical.launchpad.webapp.vhosts import allvhosts
10 from canonical.lazr import pidfile
11 from canonical.config import CanonicalConfig, config, dbconfig
12@@ -1054,6 +1055,9 @@
13 if not is_ca_available():
14 raise LayerInvariantError("Component architecture failed to load")
15
16+ # Access the cookie manager's secret to get the cache populated.
17+ # If we don't, it may issue extra queries depending on test order.
18+ canonical.launchpad.webapp.session.idmanager.secret
19 # If our request publication factories were defined using ZCML,
20 # they'd be set up by FunctionalTestSetup().setUp(). Since
21 # they're defined by Python code, we need to call that code
22
23=== modified file 'lib/devscripts/ec2test/remote.py'
24--- lib/devscripts/ec2test/remote.py 2011-02-23 11:41:12 +0000
25+++ lib/devscripts/ec2test/remote.py 2011-02-24 14:03:54 +0000
26@@ -36,20 +36,20 @@
27 import unittest
28 from xml.sax.saxutils import escape
29
30-import simplejson
31-
32 import bzrlib.branch
33 import bzrlib.config
34+from bzrlib.email_message import EmailMessage
35 import bzrlib.errors
36+from bzrlib.smtp_connection import SMTPConnection
37 import bzrlib.workingtree
38-
39-from bzrlib.email_message import EmailMessage
40-from bzrlib.smtp_connection import SMTPConnection
41-
42+import simplejson
43 import subunit
44-
45 from testtools import MultiTestResult
46
47+# We need to be able to unpickle objects from bzr-pqm, so make sure we
48+# can import it.
49+bzrlib.plugin.load_plugins()
50+
51
52 class NonZeroExitCode(Exception):
53 """Raised when the child process exits with a non-zero exit code."""
54
55=== modified file 'lib/lp/bugs/scripts/checkwatches/remotebugupdater.py'
56--- lib/lp/bugs/scripts/checkwatches/remotebugupdater.py 2011-02-23 08:57:39 +0000
57+++ lib/lp/bugs/scripts/checkwatches/remotebugupdater.py 2011-02-24 14:03:54 +0000
58@@ -13,7 +13,7 @@
59 from zope.component import getUtility
60
61 from canonical.database.constants import UTC_NOW
62-from lp.bugs.externalbugtracker import (
63+from lp.bugs.externalbugtracker.base import (
64 BugNotFound,
65 InvalidBugId,
66 PrivateRemoteBug,