diff --git a/.sphinx/_templates/header.html b/.sphinx/_templates/header.html index 54cc0a9..de1e65f 100644 --- a/.sphinx/_templates/header.html +++ b/.sphinx/_templates/header.html @@ -16,6 +16,14 @@ {{ product_page }} +
+ Staging server: all data will be discarded daily!
+ +Boolean values +-------------- + +Frequently it is desired to have a boolean feature flag that can be used +to toggle something on or off. + +Decide what the default should be with the flag unset and this should be +the \`False\` value of the boolean, so name the flag accordingly. + +Then when checking the value do a bool() of the return value and use +that as the value of the flag. + +This means that unset and the empty string are \`False\` and anything +else is \`True\` (note that this means that "false", "False", "off", 0, +etc. all mean \`True`) + +For example + +:: + + if getFeatureFlag('soyuz.frobble_the_wotsits.enabled'): + wotsit.frobble() + +Adding and documenting a new feature flag +----------------------------------------- + +If you introduce a new feature flag, as well as reading it from +whereever is useful, you should also: + +- Add a section in lib/lp/services/features/flags.py flag_info + describing the flag, including documentation that will make sense to + people not intimately involved with development of the feature. For + example: + +:: + + # This table of flag name, value domain, and prose documentation is used to + # generate the web-visible feature flag documentation. + flag_info = sorted([ + ('code.recipes_enabled', + 'boolean', + 'enable recipes', + ''), + +The last item in that list is descriptive, not prescriptive: it +*documents the code's default behavior* if no value is specified. The +flag's value will still read as None if no value is specified, and +setting it to an empty value still returns the empty string. + +Adding a new scope controller +----------------------------- + +Add a new class in + +:: + + lib/lp/services/features/scopes.py + +and make sure it's in + +:: + + HANDLERS + +in that file. (You'll normally do this by adding it to + +:: + + WEBAPP_SCOPE_HANDLERS + +and/or + +:: + + SCRIPT_SCOPE_HANDLERS + +depending on whether it applies to webapp requests, scripts, or both). + +Testing +------- + +``FeatureFixture`` uses the testtools fixtures API to hook into your code. When +it is installed on a TestCase object, the fixture will be automatically torn +down and reset between tests, restoring all of the originally set flags. + + +.. note:: + + There is one gotcha: all existing flags are wiped out by the + fixture for the duration of the test. If you want them to carry over, + you need to do so yourself.* + +You can use the fixture three different ways: + +- With the ``TestCase.useFixture()`` method +- As a context manager, using the ``with`` statement +- By directly calling a fixture instance's ``setUp()`` and ``cleanUp()`` methods + +Here is some sample code demonstrating each: + +.. code:: python + + from lp.services.features.testing import FeatureFixture + from lp.services.features import getFeatureFlag + + + class FeatureTestCase(TestCase): + + layer = DatabaseFunctionalLayer # Features need the database for now + + def test_useFixture(self): + # You can use the fixture with the useFixture() TestCase method: + self.useFixture(FeatureFixture({'reds': 'on'})) + self.assertEqual('on', getFeatureFlag('reds')) + + def test_with_context_manager(self): + # Or as a context manager: + with FeatureFixture({'blues': None}): + self.assertEqual(None, getFeatureFlag('blues')) + + def test_setUp_and_cleanUp(self): + # You can call a fixture's setUp() and cleanUp() directly. + # This is good for use in doctests. + flags = FeatureFixture({'greens': 'mu'}) + flags.setUp() + self.addCleanup(flags.cleanUp) # or use a try/finally + +For more details on using the fixture and other feature flag utilities, +check the module docs in ``lib/lp/services/features/__init__.py``. + +For sample code, check: + +- ``lib/lp/services/features/testing.py`` +- ``lib/lp/services/features/tests/test_helpers.py`` +- ``$ grep -r FeatureFixture lib/lp/`` + +Tips and traps +-------------- + +- `When you soft launch a feature limited to + launchpad-beta`` +and ``