Merge lp:~abentley/launchpad/test-feature-flags into lp:launchpad/db-devel

Proposed by Aaron Bentley
Status: Merged
Approved by: Paul Hummer
Approved revision: no longer in the source branch.
Merged at revision: 9850
Proposed branch: lp:~abentley/launchpad/test-feature-flags
Merge into: lp:launchpad/db-devel
Diff against target: 130 lines (+83/-4)
2 files modified
lib/lp/testing/__init__.py (+40/-4)
lib/lp/testing/tests/test_testing.py (+43/-0)
To merge this branch: bzr merge lp:~abentley/launchpad/test-feature-flags
Reviewer Review Type Date Requested Status
Paul Hummer (community) Approve
Review via email: mp+37061@code.launchpad.net

Commit message

Provide test helpers for feature flags.

Description of the change

= Summary =
Provide test helpers for feature flags.

== Proposed fix ==
Provide a feature_flags context manager that allows feature flags to work
Provide a set_feature_flag function that allows a feature flag to be set.

== Pre-implementation notes ==
None, but these are based on the memcache tests that Robert gave as an example
of good feature flags tests.

== Implementation details ==
None

== Tests ==
bin/test -vvt TestFeatureFlags testing

== Demo and Q/A ==
None

= Launchpad lint =

The import issues are because testing imports from other modules to provide a
central location to import from. The rest are bogus.

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/testing/__init__.py
  lib/lp/testing/tests/test_testing.py

./lib/lp/testing/__init__.py
     132: 'anonymous_logged_in' imported but unused
     132: 'with_anonymous_login' imported but unused
     132: 'is_logged_in' imported but unused
     151: 'launchpadlib_for' imported but unused
     151: 'launchpadlib_credentials_for' imported but unused
     132: 'person_logged_in' imported but unused
     151: 'oauth_access_token_for' imported but unused
     132: 'login_celebrity' imported but unused
     132: 'with_celebrity_logged_in' imported but unused
     150: 'test_tales' imported but unused
     132: 'celebrity_logged_in' imported but unused
     132: 'run_with_login' imported but unused
     132: 'with_person_logged_in' imported but unused
     132: 'login_team' imported but unused
     132: 'login_person' imported but unused
     132: 'login_as' imported but unused
     692: E301 expected 1 blank line, found 0
     875: E301 expected 1 blank line, found 0
     901: E302 expected 2 blank lines, found 1
     977: E302 expected 2 blank lines, found 1

To post a comment you must log in.
Revision history for this message
Paul Hummer (rockstar) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/testing/__init__.py'
--- lib/lp/testing/__init__.py 2010-09-22 18:37:57 +0000
+++ lib/lp/testing/__init__.py 2010-09-29 20:38:55 +0000
@@ -112,7 +112,10 @@
112 )112 )
113from canonical.launchpad.webapp.errorlog import ErrorReportEvent113from canonical.launchpad.webapp.errorlog import ErrorReportEvent
114from canonical.launchpad.webapp.interaction import ANONYMOUS114from canonical.launchpad.webapp.interaction import ANONYMOUS
115from canonical.launchpad.webapp.servers import WebServiceTestRequest115from canonical.launchpad.webapp.servers import (
116 LaunchpadTestRequest,
117 WebServiceTestRequest,
118 )
116from canonical.launchpad.windmill.testing import constants119from canonical.launchpad.windmill.testing import constants
117from lp.codehosting.vfs import (120from lp.codehosting.vfs import (
118 branch_id_to_path,121 branch_id_to_path,
@@ -120,6 +123,10 @@
120 )123 )
121from lp.registry.interfaces.packaging import IPackagingUtil124from lp.registry.interfaces.packaging import IPackagingUtil
122from lp.services.osutils import override_environ125from lp.services.osutils import override_environ
126from lp.services import features
127from lp.services.features.flags import FeatureController
128from lp.services.features.model import getFeatureStore, FeatureFlag
129from lp.services.features.webapp import ScopesFromRequest
123# Import the login helper functions here as it is a much better130# Import the login helper functions here as it is a much better
124# place to import them from in tests.131# place to import them from in tests.
125from lp.testing._login import (132from lp.testing._login import (
@@ -222,9 +229,10 @@
222229
223class StormStatementRecorder:230class StormStatementRecorder:
224 """A storm tracer to count queries.231 """A storm tracer to count queries.
225 232
226 This exposes the count and queries as lp.testing._webservice.QueryCollector233 This exposes the count and queries as
227 does permitting its use with the HasQueryCount matcher.234 lp.testing._webservice.QueryCollector does permitting its use with the
235 HasQueryCount matcher.
228236
229 It also meets the context manager protocol, so you can gather queries237 It also meets the context manager protocol, so you can gather queries
230 easily:238 easily:
@@ -875,6 +883,19 @@
875 zope.event.subscribers[:] = old_subscribers883 zope.event.subscribers[:] = old_subscribers
876884
877885
886@contextmanager
887def feature_flags():
888 """Provide a context in which feature flags work."""
889 empty_request = LaunchpadTestRequest()
890 old_features = getattr(features.per_thread, 'features', None)
891 features.per_thread.features = FeatureController(
892 ScopesFromRequest(empty_request).lookup)
893 try:
894 yield
895 finally:
896 features.per_thread.features = old_features
897
898
878# XXX: This doesn't seem like a generically-useful testing function. Perhaps899# XXX: This doesn't seem like a generically-useful testing function. Perhaps
879# it should go in a sub-module or something? -- jml900# it should go in a sub-module or something? -- jml
880def get_lsb_information():901def get_lsb_information():
@@ -977,6 +998,21 @@
977 return contents998 return contents
978999
9791000
1001def set_feature_flag(name, value, scope=u'default', priority=1):
1002 """Set a feature flag to the specified value.
1003
1004 In order to access the flag, use the feature_flags context manager or
1005 populate features.per_thread.features some other way.
1006 :param name: The name of the flag.
1007 :param value: The value of the flag.
1008 :param scope: The scope in which the specified value applies.
1009 """
1010 assert getattr(features.per_thread, 'features', None) is not None
1011 flag = FeatureFlag(
1012 scope=scope, flag=name, value=value, priority=priority)
1013 getFeatureStore().add(flag)
1014
1015
980def validate_mock_class(mock_class):1016def validate_mock_class(mock_class):
981 """Validate method signatures in mock classes derived from real classes.1017 """Validate method signatures in mock classes derived from real classes.
9821018
9831019
=== added file 'lib/lp/testing/tests/test_testing.py'
--- lib/lp/testing/tests/test_testing.py 1970-01-01 00:00:00 +0000
+++ lib/lp/testing/tests/test_testing.py 2010-09-29 20:38:55 +0000
@@ -0,0 +1,43 @@
1# Copyright 2010 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4from __future__ import with_statement
5
6"""Tests for the testing module."""
7
8__metaclass__ = type
9
10import unittest
11
12from canonical.testing.layers import DatabaseFunctionalLayer
13from lp.services.features import getFeatureFlag
14from lp.testing import (
15 feature_flags,
16 set_feature_flag,
17 TestCase,
18 )
19
20
21class TestFeatureFlags(TestCase):
22
23 layer = DatabaseFunctionalLayer
24
25 def test_set_feature_flags_raises_if_not_available(self):
26 """set_feature_flags prevents mistakes mistakes by raising."""
27 self.assertRaises(AssertionError, set_feature_flag, u'name', u'value')
28
29 def test_flags_set_within_feature_flags_context(self):
30 """In the feature_flags context, set/get works."""
31 self.useContext(feature_flags())
32 set_feature_flag(u'name', u'value')
33 self.assertEqual('value', getFeatureFlag('name'))
34
35 def test_flags_unset_outside_feature_flags_context(self):
36 """get fails when used outside the feature_flags context."""
37 with feature_flags():
38 set_feature_flag(u'name', u'value')
39 self.assertIs(None, getFeatureFlag('name'))
40
41
42def test_suite():
43 return unittest.TestLoader().loadTestsFromName(__name__)

Subscribers

People subscribed via source and target branches

to status/vote changes: