~launchpad-pqm/launchpad/devel

10197.5.13 by Michael Hudson
misc. fixes
1
# Copyright 2009, 2010 Canonical Ltd.  This software is licensed under the
8687.15.22 by Karl Fogel
Add the copyright header block to the remaining .py files.
2
# GNU Affero General Public License version 3 (see the file LICENSE).
3
11731.1.1 by Robert Collins
Rationalise our fixture test support - delete unused stuff, consolidate on the external fixtures API.
4
"""Launchpad test fixtures that have no better home."""
7960.4.30 by Jonathan Lange
Basic fixture support.
5
6
__metaclass__ = type
7960.4.32 by Jonathan Lange
Add a fixture that has addCleanup support.
7
__all__ = [
13333.6.50 by Gavin Panella
Set the service_config in a new RabbitServer fixture.
8
    'RabbitServer',
13333.6.35 by Gavin Panella
Move AdapterFixture to lp.testing.fixture.ZopeAdapterFixture.
9
    'ZopeAdapterFixture',
11731.1.1 by Robert Collins
Rationalise our fixture test support - delete unused stuff, consolidate on the external fixtures API.
10
    'ZopeEventHandlerFixture',
13333.6.35 by Gavin Panella
Move AdapterFixture to lp.testing.fixture.ZopeAdapterFixture.
11
    'ZopeViewReplacementFixture',
7960.4.32 by Jonathan Lange
Add a fixture that has addCleanup support.
12
    ]
7960.4.30 by Jonathan Lange
Basic fixture support.
13
13813.1.6 by Stuart Bishop
Revert reversion in launchpad/devel r13865
14
from ConfigParser import SafeConfigParser
15
import os.path
13333.6.50 by Gavin Panella
Set the service_config in a new RabbitServer fixture.
16
from textwrap import dedent
17
13813.1.6 by Stuart Bishop
Revert reversion in launchpad/devel r13865
18
from fixtures import (
19
    EnvironmentVariableFixture,
20
    Fixture,
21
    )
22
import pgbouncer.fixture
13333.6.50 by Gavin Panella
Set the service_config in a new RabbitServer fixture.
23
import rabbitfixture.server
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
24
from zope.component import (
25
    getGlobalSiteManager,
26
    provideHandler,
27
    )
13195.1.1 by Gary Poster
openid discovery failure should not record an OOPS. Add a new Zope view replacement test fixture to help.
28
from zope.interface import Interface
29
from zope.publisher.interfaces.browser import IDefaultBrowserLayer
30
from zope.security.checker import (
31
    defineChecker,
32
    getCheckerForInstancesOf,
33
    undefineChecker,
34
    )
11731.1.1 by Robert Collins
Rationalise our fixture test support - delete unused stuff, consolidate on the external fixtures API.
35
13813.1.6 by Stuart Bishop
Revert reversion in launchpad/devel r13865
36
from canonical.config import config
37
11731.1.1 by Robert Collins
Rationalise our fixture test support - delete unused stuff, consolidate on the external fixtures API.
38
13333.6.50 by Gavin Panella
Set the service_config in a new RabbitServer fixture.
39
class RabbitServer(rabbitfixture.server.RabbitServer):
40
    """A RabbitMQ server fixture with Launchpad-specific config.
41
42
    :ivar service_config: A snippet of .ini that describes the `rabbitmq`
43
        configuration.
44
    """
45
46
    def setUp(self):
47
        super(RabbitServer, self).setUp()
48
        self.config.service_config = dedent("""\
49
            [rabbitmq]
50
            host: localhost:%d
51
            userid: guest
52
            password: guest
53
            virtual_host: /
54
            """ % self.config.port)
55
56
13813.1.6 by Stuart Bishop
Revert reversion in launchpad/devel r13865
57
class PGBouncerFixture(pgbouncer.fixture.PGBouncerFixture):
58
    """Inserts a controllable pgbouncer instance in front of PostgreSQL.
59
60
    The pgbouncer proxy can be shutdown and restarted at will, simulating
61
    database outages and fastdowntime deployments.
62
    """
63
64
    def __init__(self):
65
        super(PGBouncerFixture, self).__init__()
66
67
        # Known databases
68
        from canonical.testing.layers import DatabaseLayer
69
        dbnames = [
70
            DatabaseLayer._db_fixture.dbname,
71
            DatabaseLayer._db_template_fixture.dbname,
72
            'session_ftest',
73
            'launchpad_empty',
74
            ]
75
        for dbname in dbnames:
76
            self.databases[dbname] = 'dbname=%s port=5432 host=localhost' % (
77
                dbname,)
78
79
        # Known users, pulled from security.cfg
80
        security_cfg_path = os.path.join(
81
            config.root, 'database', 'schema', 'security.cfg')
82
        security_cfg_config = SafeConfigParser({})
83
        security_cfg_config.read([security_cfg_path])
84
        for section_name in security_cfg_config.sections():
85
            self.users[section_name] = 'trusted'
86
            self.users[section_name + '_ro'] = 'trusted'
87
        self.users[os.environ['USER']] = 'trusted'
88
89
    def setUp(self):
90
        super(PGBouncerFixture, self).setUp()
91
92
        # reconnect_store cleanup added first so it is run last, after
93
        # the environment variables have been reset.
94
        self.addCleanup(self._maybe_reconnect_stores)
95
96
        # Abuse the PGPORT environment variable to get things connecting
97
        # via pgbouncer. Otherwise, we would need to temporarily
98
        # overwrite the database connection strings in the config.
99
        self.useFixture(EnvironmentVariableFixture('PGPORT', str(self.port)))
100
101
        # Reset database connections so they go through pgbouncer.
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()
117
118
13333.6.35 by Gavin Panella
Move AdapterFixture to lp.testing.fixture.ZopeAdapterFixture.
119
class ZopeAdapterFixture(Fixture):
120
    """A fixture to register and unregister an adapter."""
121
122
    def __init__(self, *args, **kwargs):
123
        self._args, self._kwargs = args, kwargs
124
125
    def setUp(self):
126
        super(ZopeAdapterFixture, self).setUp()
127
        site_manager = getGlobalSiteManager()
128
        site_manager.registerAdapter(
129
            *self._args, **self._kwargs)
130
        self.addCleanup(
131
            site_manager.unregisterAdapter,
132
            *self._args, **self._kwargs)
133
134
11731.1.1 by Robert Collins
Rationalise our fixture test support - delete unused stuff, consolidate on the external fixtures API.
135
class ZopeEventHandlerFixture(Fixture):
7960.4.39 by Jonathan Lange
Move the zope code to the fixture module.
136
    """A fixture that provides and then unprovides a Zope event handler."""
137
138
    def __init__(self, handler):
11731.1.1 by Robert Collins
Rationalise our fixture test support - delete unused stuff, consolidate on the external fixtures API.
139
        super(ZopeEventHandlerFixture, self).__init__()
7960.4.39 by Jonathan Lange
Move the zope code to the fixture module.
140
        self._handler = handler
141
142
    def setUp(self):
143
        super(ZopeEventHandlerFixture, self).setUp()
144
        gsm = getGlobalSiteManager()
145
        provideHandler(self._handler)
146
        self.addCleanup(gsm.unregisterHandler, self._handler)
13195.1.1 by Gary Poster
openid discovery failure should not record an OOPS. Add a new Zope view replacement test fixture to help.
147
148
149
class ZopeViewReplacementFixture(Fixture):
150
    """A fixture that allows you to temporarily replace one view with another.
13195.1.2 by Gary Poster
fix lint
151
13195.1.1 by Gary Poster
openid discovery failure should not record an OOPS. Add a new Zope view replacement test fixture to help.
152
    This will not work with the AppServerLayer.
153
    """
154
155
    def __init__(self, name, context_interface,
156
                 request_interface=IDefaultBrowserLayer,
157
                 replacement=None):
158
        super(ZopeViewReplacementFixture, self).__init__()
159
        self.name = name
160
        self.context_interface = context_interface
161
        self.request_interface = request_interface
162
        self.gsm = getGlobalSiteManager()
163
        # It can be convenient--bordering on necessary--to use this original
164
        # class as a base for the replacement.
165
        self.original = self.gsm.adapters.registered(
166
            (context_interface, request_interface), Interface, name)
167
        self.checker = getCheckerForInstancesOf(self.original)
168
        if self.original is None:
169
            # The adapter registry does not provide good methods to introspect
170
            # it. If it did, we might try harder here.
171
            raise ValueError(
172
                'No existing view to replace.  Wrong request interface?  '
173
                'Try a layer.')
174
        self.replacement = replacement
175
176
    def setUp(self):
177
        super(ZopeViewReplacementFixture, self).setUp()
178
        if self.replacement is None:
179
            raise ValueError('replacement is not set')
180
        self.gsm.adapters.register(
181
            (self.context_interface, self.request_interface), Interface,
182
             self.name, self.replacement)
183
        # The same checker should be sufficient.  If it ever isn't, we
184
        # can add more flexibility then.
185
        defineChecker(self.replacement, self.checker)
186
187
    def tearDown(self):
188
        super(ZopeViewReplacementFixture, self).tearDown()
189
        undefineChecker(self.replacement)
190
        self.gsm.adapters.register(
191
            (self.context_interface, self.request_interface), Interface,
192
             self.name, self.original)