nti.testing 4.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nti/__init__.py +0 -0
- nti/testing/__init__.py +107 -0
- nti/testing/base.py +574 -0
- nti/testing/layers/__init__.py +53 -0
- nti/testing/layers/cleanup.py +106 -0
- nti/testing/layers/postgres.py +693 -0
- nti/testing/layers/tests/__init__.py +0 -0
- nti/testing/layers/tests/test_postgres.py +17 -0
- nti/testing/layers/zope.py +122 -0
- nti/testing/matchers.py +370 -0
- nti/testing/mock.py +22 -0
- nti/testing/tests/__init__.py +0 -0
- nti/testing/tests/test_base.py +160 -0
- nti/testing/tests/test_component_cleanup_broken.txt +137 -0
- nti/testing/tests/test_layers.py +56 -0
- nti/testing/tests/test_main.py +47 -0
- nti/testing/tests/test_matchers.py +237 -0
- nti/testing/tests/test_time.py +157 -0
- nti/testing/tests/test_zodb.py +326 -0
- nti/testing/time.py +179 -0
- nti/testing/zodb.py +245 -0
- nti.testing-4.2.0.dist-info/LICENSE +11 -0
- nti.testing-4.2.0.dist-info/METADATA +423 -0
- nti.testing-4.2.0.dist-info/RECORD +27 -0
- nti.testing-4.2.0.dist-info/WHEEL +5 -0
- nti.testing-4.2.0.dist-info/top_level.txt +1 -0
- nti.testing-4.2.0.dist-info/zip-safe +1 -0
nti/__init__.py
ADDED
|
File without changes
|
nti/testing/__init__.py
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
The ``nti.testing`` module exposes the most commonly used API from the
|
|
5
|
+
submodules (for example, ``nti.testing.is_true`` is just an alias for
|
|
6
|
+
``nti.testing.matchers.is_true``). The submodules may contain other
|
|
7
|
+
functions, though, so be sure to look at their documentation.
|
|
8
|
+
|
|
9
|
+
Importing this module has side-effects when :mod:`zope.testing` is
|
|
10
|
+
importable:
|
|
11
|
+
|
|
12
|
+
- Add a zope.testing cleanup to ensure that transactions never
|
|
13
|
+
last past the boundary of a test. If a test begins a transaction
|
|
14
|
+
and then fails to abort or commit it, subsequent uses of the
|
|
15
|
+
transaction package may find that they are in a bad state,
|
|
16
|
+
unable to clean up resources. For example, the dreaded
|
|
17
|
+
``ConnectionStateError: Cannot close a connection joined to a
|
|
18
|
+
transaction``.
|
|
19
|
+
|
|
20
|
+
- A zope.testing cleanup also ensures that the global transaction
|
|
21
|
+
manager is in its default implicit mode, at least for the
|
|
22
|
+
current thread.
|
|
23
|
+
|
|
24
|
+
.. versionchanged:: 3.1.0
|
|
25
|
+
|
|
26
|
+
The :mod:`mock` module, or its backwards compatibility backport for
|
|
27
|
+
Python 2.7, is now available as an attribute of this module, and as
|
|
28
|
+
the module named ``nti.testing.mock``. Thus, for compatibility with
|
|
29
|
+
both Python 2 and Python 3, you can write ``from nti.testing import
|
|
30
|
+
mock`` or ``from nti.testing.mock import Mock``, or even just
|
|
31
|
+
``from nti.testing import Mock``.
|
|
32
|
+
|
|
33
|
+
.. versionchanged:: 3.1.0
|
|
34
|
+
|
|
35
|
+
Expose the most commonly used attributes of some submodules as API on this
|
|
36
|
+
module itself.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
from __future__ import absolute_import
|
|
40
|
+
from __future__ import division
|
|
41
|
+
from __future__ import print_function
|
|
42
|
+
|
|
43
|
+
import transaction
|
|
44
|
+
import zope.testing.cleanup
|
|
45
|
+
|
|
46
|
+
from . import mock
|
|
47
|
+
from .mock import Mock
|
|
48
|
+
|
|
49
|
+
from .matchers import is_true
|
|
50
|
+
from .matchers import is_false
|
|
51
|
+
from .matchers import provides
|
|
52
|
+
from .matchers import implements
|
|
53
|
+
from .matchers import verifiably_provides
|
|
54
|
+
from .matchers import validly_provides
|
|
55
|
+
from .matchers import validated_by
|
|
56
|
+
from .matchers import not_validated_by
|
|
57
|
+
from .matchers import aq_inContextOf
|
|
58
|
+
|
|
59
|
+
from .time import time_monotonically_increases
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
__docformat__ = "restructuredtext en"
|
|
63
|
+
|
|
64
|
+
def transactionCleanUp():
|
|
65
|
+
"""
|
|
66
|
+
Implement the transaction cleanup described in the module documentation.
|
|
67
|
+
"""
|
|
68
|
+
try:
|
|
69
|
+
transaction.abort()
|
|
70
|
+
except transaction.interfaces.NoTransaction:
|
|
71
|
+
# An explicit transaction manager, with nothing
|
|
72
|
+
# to do. Perfect.
|
|
73
|
+
pass
|
|
74
|
+
finally:
|
|
75
|
+
# Note that we don't catch any other transaction errors.
|
|
76
|
+
# Those usually mean there's a bug in a resource manager joined
|
|
77
|
+
# to the transaction and it should fail the test.
|
|
78
|
+
transaction.manager.explicit = False
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
zope.testing.cleanup.addCleanUp(transactionCleanUp)
|
|
82
|
+
|
|
83
|
+
__all__ = [
|
|
84
|
+
# Things defined here we want to export
|
|
85
|
+
# if they do 'from nti.testing import *'
|
|
86
|
+
# This also defines what Sphinx documents for this module.
|
|
87
|
+
'transactionCleanUp',
|
|
88
|
+
'mock',
|
|
89
|
+
'Mock',
|
|
90
|
+
# API Convenience exports.
|
|
91
|
+
# * matchers
|
|
92
|
+
'is_true',
|
|
93
|
+
'is_false',
|
|
94
|
+
'provides',
|
|
95
|
+
'implements',
|
|
96
|
+
'verifiably_provides',
|
|
97
|
+
'validly_provides',
|
|
98
|
+
'provides',
|
|
99
|
+
'validated_by',
|
|
100
|
+
'not_validated_by',
|
|
101
|
+
'aq_inContextOf',
|
|
102
|
+
# * time
|
|
103
|
+
'time_monotonically_increases',
|
|
104
|
+
# Sub-modules that should be imported with
|
|
105
|
+
# * imports as well. We generally don't want anything
|
|
106
|
+
# imported; it's better to use direct imports.
|
|
107
|
+
]
|
nti/testing/base.py
ADDED
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Base test classes and functions for setting up ZCA.
|
|
5
|
+
|
|
6
|
+
In some cases, you may be better off using :mod:`zope.component.testlayer`.
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import absolute_import
|
|
11
|
+
from __future__ import division
|
|
12
|
+
from __future__ import print_function
|
|
13
|
+
|
|
14
|
+
# stdlib imports
|
|
15
|
+
import gc
|
|
16
|
+
import os
|
|
17
|
+
import platform
|
|
18
|
+
import sys
|
|
19
|
+
import unittest
|
|
20
|
+
from unittest.mock import patch as Patch
|
|
21
|
+
|
|
22
|
+
from zope import component
|
|
23
|
+
from zope.component import eventtesting
|
|
24
|
+
from zope.component.hooks import setHooks
|
|
25
|
+
from zope.configuration import config
|
|
26
|
+
from zope.configuration import xmlconfig
|
|
27
|
+
from zope.dottedname import resolve as dottedname
|
|
28
|
+
import zope.testing.cleanup
|
|
29
|
+
|
|
30
|
+
from hamcrest import assert_that
|
|
31
|
+
from hamcrest import is_
|
|
32
|
+
|
|
33
|
+
from . import transactionCleanUp
|
|
34
|
+
|
|
35
|
+
logger = __import__('logging').getLogger(__name__)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
_marker = object()
|
|
39
|
+
|
|
40
|
+
class AbstractConfiguringObject(object):
|
|
41
|
+
"""
|
|
42
|
+
A class for executing ZCML configuration.
|
|
43
|
+
|
|
44
|
+
Other than the attributes that are documented on this class,
|
|
45
|
+
users are not expected to use this class or subclass it.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
#: Class attribute naming a sequence of package objects or strings
|
|
49
|
+
#: naming packages. These will be configured, in order, using
|
|
50
|
+
#: ZCML. The ``configure.zcml`` package from each package will be
|
|
51
|
+
#: loaded. Instead of a package object, each item can be a tuple
|
|
52
|
+
#: of (filename, package); in that case, the given file (usually
|
|
53
|
+
#: ``meta.zcml``) will be loaded from the given package.
|
|
54
|
+
set_up_packages = ()
|
|
55
|
+
|
|
56
|
+
#: Class attribute naming a sequence of strings to be added as
|
|
57
|
+
#: features before loading the configuration. By default, this is
|
|
58
|
+
#: ``devmode`` and ``testmode``. (Devmode is suitable for running
|
|
59
|
+
#: the application, testmode is only suitable for unit tests.)
|
|
60
|
+
features = ('devmode', 'testmode')
|
|
61
|
+
|
|
62
|
+
#: Class attribute that is a boolean defaulting to True. When
|
|
63
|
+
#: true, the :mod:`zope.component.eventtesting` module will be
|
|
64
|
+
#: configured.
|
|
65
|
+
#:
|
|
66
|
+
#: .. note:: If there are any ``set_up_packages`` you are
|
|
67
|
+
#: responsible for ensuring that the :mod:`zope.component`
|
|
68
|
+
#: configuration is loaded.
|
|
69
|
+
configure_events = True
|
|
70
|
+
|
|
71
|
+
#: Instance attribute defined by :meth:`setUp` that is the :class:`~.ConfigurationMachine`
|
|
72
|
+
#: that was used to load configuration data (if any). This can be
|
|
73
|
+
#: used by individual methods to load more configuration data
|
|
74
|
+
#: using :meth:`configure_packages` or the methods from
|
|
75
|
+
#: :mod:`zope.configuration`
|
|
76
|
+
configuration_context = None
|
|
77
|
+
|
|
78
|
+
@staticmethod
|
|
79
|
+
def _doSetUp(obj):
|
|
80
|
+
obj._doSetUpSuper() # pylint:disable=protected-access
|
|
81
|
+
setHooks() # zope.component.hooks registers a zope.testing.cleanup to reset these
|
|
82
|
+
if obj.configure_events:
|
|
83
|
+
if obj.set_up_packages:
|
|
84
|
+
# If zope.component is being configured, we wind up with duplicates if we let
|
|
85
|
+
# eventtesting fully configure itself
|
|
86
|
+
component.provideHandler(eventtesting.events.append, (None,))
|
|
87
|
+
else:
|
|
88
|
+
eventtesting.setUp() # pragma: no cover
|
|
89
|
+
|
|
90
|
+
obj.configuration_context = obj.configure_packages(
|
|
91
|
+
set_up_packages=obj.set_up_packages,
|
|
92
|
+
features=obj.features,
|
|
93
|
+
context=obj.configuration_context,
|
|
94
|
+
package=obj.get_configuration_package())
|
|
95
|
+
|
|
96
|
+
@staticmethod
|
|
97
|
+
def _do_configure_packages(obj, # pylint:disable=too-many-positional-arguments
|
|
98
|
+
set_up_packages=(),
|
|
99
|
+
features=(),
|
|
100
|
+
context=_marker,
|
|
101
|
+
configure_events=True, # pylint:disable=unused-argument
|
|
102
|
+
package=None):
|
|
103
|
+
obj.configuration_context = _configure(
|
|
104
|
+
obj,
|
|
105
|
+
set_up_packages=set_up_packages,
|
|
106
|
+
features=features,
|
|
107
|
+
context=(context if context is not _marker else obj.configuration_context),
|
|
108
|
+
package=package)
|
|
109
|
+
return obj.configuration_context
|
|
110
|
+
|
|
111
|
+
@staticmethod
|
|
112
|
+
def _doTearDown(obj, clear_configuration_context=True, super_tear_down=None):
|
|
113
|
+
# always safe to clear events
|
|
114
|
+
eventtesting.clearEvents() # redundant with zope.testing.cleanup
|
|
115
|
+
# we never actually want to do this, it's not needed and can mess up other fixtures
|
|
116
|
+
# resetHooks()
|
|
117
|
+
transactionCleanUp()
|
|
118
|
+
if clear_configuration_context:
|
|
119
|
+
obj.configuration_context = None
|
|
120
|
+
if super_tear_down is not None:
|
|
121
|
+
super_tear_down()
|
|
122
|
+
else:
|
|
123
|
+
obj._doTearDownSuper() # pylint:disable=protected-access
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@staticmethod
|
|
127
|
+
def get_configuration_package_for_class(klass):
|
|
128
|
+
"""
|
|
129
|
+
Return the package that ``.`` means when configuring packages.
|
|
130
|
+
|
|
131
|
+
For test classes that exist in a subpackage called ``tests`` in
|
|
132
|
+
a module beginning with ``test``, this defaults to the parent
|
|
133
|
+
package. E.g., if *klass* is
|
|
134
|
+
``nti.appserver.tests.test_app.TestApp`` then this is
|
|
135
|
+
``nti.appserver``.
|
|
136
|
+
"""
|
|
137
|
+
module = klass.__module__
|
|
138
|
+
if not module: # pragma: no cover
|
|
139
|
+
return None
|
|
140
|
+
|
|
141
|
+
module_parts = module.split('.')
|
|
142
|
+
if module_parts[-1].startswith('test') and module_parts[-2] == 'tests':
|
|
143
|
+
module = '.'.join(module_parts[0:-2])
|
|
144
|
+
|
|
145
|
+
package = sys.modules[module]
|
|
146
|
+
return package
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class PatchingMixin:
|
|
150
|
+
"""
|
|
151
|
+
Mixin class adding support for dynamic :mod:`unittest.mock` patches.
|
|
152
|
+
|
|
153
|
+
.. versionadded:: 4.0.0
|
|
154
|
+
"""
|
|
155
|
+
def patch(self, *args, **kwargs):
|
|
156
|
+
"""
|
|
157
|
+
API for subclasses. All args are passed through to :obj:`unittest.mock.patch`
|
|
158
|
+
which is then started and registered for cleanup.
|
|
159
|
+
|
|
160
|
+
This is intended to be used in ``setUp`` or individual test methods
|
|
161
|
+
when what you might need to patch is dynamic.
|
|
162
|
+
|
|
163
|
+
Returns the result of ``patch.start()``, i.e., a mock object.
|
|
164
|
+
|
|
165
|
+
.. versionadded:: 4.0.0
|
|
166
|
+
"""
|
|
167
|
+
return self._install_patch(Patch(*args, **kwargs))
|
|
168
|
+
|
|
169
|
+
def _install_patch(self, patcher):
|
|
170
|
+
"""
|
|
171
|
+
Starts the *patcher*, and registers a test tear down cleanup
|
|
172
|
+
to stop it.
|
|
173
|
+
|
|
174
|
+
Returns the result of ``patcher.start``
|
|
175
|
+
"""
|
|
176
|
+
result = patcher.start()
|
|
177
|
+
self.addCleanup(patcher.stop)
|
|
178
|
+
return result
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class AbstractTestBase(zope.testing.cleanup.CleanUp,
|
|
182
|
+
PatchingMixin,
|
|
183
|
+
unittest.TestCase):
|
|
184
|
+
"""
|
|
185
|
+
Base class for testing. Inherits the setup and teardown functions for
|
|
186
|
+
:class:`zope.testing.cleanup.CleanUp`; one effect this has is to cause
|
|
187
|
+
the component registry to be reset after every test.
|
|
188
|
+
|
|
189
|
+
.. note:: Do not use this when you use :func:`module_setup` and
|
|
190
|
+
:func:`module_teardown`, as the inherited :meth:`setUp` will
|
|
191
|
+
undo the effects of the module setup.
|
|
192
|
+
"""
|
|
193
|
+
|
|
194
|
+
def get_configuration_package(self):
|
|
195
|
+
"""
|
|
196
|
+
See :meth:`AbstractConfiguringObject.get_configuration_package_for_class`.
|
|
197
|
+
"""
|
|
198
|
+
return AbstractConfiguringObject.get_configuration_package_for_class(self.__class__)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
_shared_cleanups = []
|
|
203
|
+
|
|
204
|
+
def addSharedCleanUp(func, args=(), kw=None):
|
|
205
|
+
"""
|
|
206
|
+
Registers a cleanup to happen for every test, regardless of whether
|
|
207
|
+
the test is using shared configuration or not.
|
|
208
|
+
"""
|
|
209
|
+
_shared_cleanups.append((func, args, kw or {}))
|
|
210
|
+
zope.testing.cleanup.addCleanUp(func, args, kw or {})
|
|
211
|
+
|
|
212
|
+
def sharedCleanup():
|
|
213
|
+
"""
|
|
214
|
+
Clean up things that should be cleared for every test, even
|
|
215
|
+
in a shared test base.
|
|
216
|
+
"""
|
|
217
|
+
for func, args, kw in _shared_cleanups:
|
|
218
|
+
func(*args, **kw)
|
|
219
|
+
|
|
220
|
+
class SharedTestBaseMetaclass(type):
|
|
221
|
+
"""
|
|
222
|
+
A metaclass that converts the nose-specific use of ``setUpClass``
|
|
223
|
+
and ``tearDownClass`` into a layer that also works with zope.testrunner
|
|
224
|
+
(which is generally better than nose2).
|
|
225
|
+
|
|
226
|
+
This works because nose2 picks one or the other, and it chooses layers
|
|
227
|
+
over setUp/tearDownClass---only one of them is called. (If that changes,
|
|
228
|
+
it's easy to workaround.)
|
|
229
|
+
"""
|
|
230
|
+
|
|
231
|
+
def __new__(mcs, name, bases, cdict): # pylint:disable=bad-mcs-classmethod-argument
|
|
232
|
+
the_type = type.__new__(mcs, name, bases, cdict)
|
|
233
|
+
# TODO: Based on certain features of the the_type
|
|
234
|
+
# like set_up_packages and features, we can probably
|
|
235
|
+
# cache and share layers, which will help speed up
|
|
236
|
+
# test runs
|
|
237
|
+
class layer(object):
|
|
238
|
+
__name__ = name
|
|
239
|
+
__mro__ = __bases__ = (object,)
|
|
240
|
+
|
|
241
|
+
@classmethod
|
|
242
|
+
def setUp(cls):
|
|
243
|
+
the_type.setUpClass()
|
|
244
|
+
@classmethod
|
|
245
|
+
def tearDown(cls):
|
|
246
|
+
the_type.tearDownClass()
|
|
247
|
+
@classmethod
|
|
248
|
+
def testSetUp(cls):
|
|
249
|
+
pass
|
|
250
|
+
@classmethod
|
|
251
|
+
def testTearDown(cls):
|
|
252
|
+
pass
|
|
253
|
+
the_type.layer = layer
|
|
254
|
+
layer.__name__ = name
|
|
255
|
+
return the_type
|
|
256
|
+
|
|
257
|
+
_is_pypy = platform.python_implementation() == 'PyPy'
|
|
258
|
+
|
|
259
|
+
class AbstractSharedTestBase(PatchingMixin,
|
|
260
|
+
unittest.TestCase,
|
|
261
|
+
metaclass=SharedTestBaseMetaclass,):
|
|
262
|
+
"""
|
|
263
|
+
Base class for testing that can share most global data (e.g., ZCML
|
|
264
|
+
configuration) between unit tests. This is far more efficient, if
|
|
265
|
+
the global data (e.g., ZCA component registry) is otherwise
|
|
266
|
+
cleaned up or not mutated between tests.
|
|
267
|
+
|
|
268
|
+
Under zope.testing and nose2, this is handled by treating the class
|
|
269
|
+
as a *layer* through :class:`SharedTestBaseMetaclass`.
|
|
270
|
+
|
|
271
|
+
"""
|
|
272
|
+
|
|
273
|
+
#: Class-level attribute that determines whether
|
|
274
|
+
#: we should only collect garbage when tearing down the class.
|
|
275
|
+
HANDLE_GC = False
|
|
276
|
+
|
|
277
|
+
@classmethod
|
|
278
|
+
def setUpClass(cls):
|
|
279
|
+
"""
|
|
280
|
+
Subclasses must call this method. It cleans up the global state.
|
|
281
|
+
|
|
282
|
+
It also disables garbage collection until
|
|
283
|
+
:meth:`tearDownClass` is called if :attr:`HANDLE_GC` is True. This
|
|
284
|
+
way, we can collect just one generation and be sure to clean
|
|
285
|
+
up any weak references that were created during this run.
|
|
286
|
+
(Which is necessary, as ZCA heavily uses weak references, and
|
|
287
|
+
when that is mixed with IComponents instances that are in a
|
|
288
|
+
ZODB, if weak references persist and aren't cleaned, bad
|
|
289
|
+
things can happen. See ``nti.dataserver.site`` for details.)
|
|
290
|
+
This is ``False`` by default for speed; set it to true if your
|
|
291
|
+
TestCase will be creating new (possibly synthetic) sites/site
|
|
292
|
+
managers.
|
|
293
|
+
"""
|
|
294
|
+
|
|
295
|
+
zope.testing.cleanup.cleanUp()
|
|
296
|
+
if cls.HANDLE_GC:
|
|
297
|
+
cls.__isenabled = gc.isenabled()
|
|
298
|
+
if not _is_pypy:
|
|
299
|
+
gc.disable() # PyPy GC is fast
|
|
300
|
+
|
|
301
|
+
@classmethod
|
|
302
|
+
def tearDownClass(cls):
|
|
303
|
+
"""
|
|
304
|
+
Subclasses must call this method. It cleans up global state
|
|
305
|
+
and performs garbage collection if :attr:`HANDLE_GC` is true.
|
|
306
|
+
"""
|
|
307
|
+
zope.testing.cleanup.cleanUp()
|
|
308
|
+
if cls.HANDLE_GC:
|
|
309
|
+
if cls.__isenabled:
|
|
310
|
+
gc.enable()
|
|
311
|
+
|
|
312
|
+
gc.collect(0) # collect now to clean up weak refs
|
|
313
|
+
gc.collect(0) # PyPy sometimes needs two cycles to get them all
|
|
314
|
+
|
|
315
|
+
assert_that(gc.garbage, is_([]))
|
|
316
|
+
|
|
317
|
+
def setUp(self):
|
|
318
|
+
"""
|
|
319
|
+
Invokes :func:`sharedCleanup` for every test.
|
|
320
|
+
"""
|
|
321
|
+
sharedCleanup()
|
|
322
|
+
|
|
323
|
+
def tearDown(self):
|
|
324
|
+
"""
|
|
325
|
+
Invokes :func:`sharedCleanup` for every test.
|
|
326
|
+
"""
|
|
327
|
+
sharedCleanup()
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def _configure(self=None,
|
|
332
|
+
set_up_packages=(),
|
|
333
|
+
features=('devmode', 'testmode'),
|
|
334
|
+
context=None,
|
|
335
|
+
package=None):
|
|
336
|
+
|
|
337
|
+
features = set(features) if features is not None else set()
|
|
338
|
+
|
|
339
|
+
# This is normally created by a slug, but tests may not always
|
|
340
|
+
# load the slug
|
|
341
|
+
if os.getenv('DATASERVER_DIR_IS_BUILDOUT'): # pragma: no cover
|
|
342
|
+
features.add('in-buildout')
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
# zope.component.globalregistry conveniently adds
|
|
346
|
+
# a zope.testing.cleanup.CleanUp to reset the globalSiteManager
|
|
347
|
+
if context is None and (features or package):
|
|
348
|
+
context = config.ConfigurationMachine()
|
|
349
|
+
context.package = package
|
|
350
|
+
xmlconfig.registerCommonDirectives(context)
|
|
351
|
+
|
|
352
|
+
for feature in features:
|
|
353
|
+
context.provideFeature(feature)
|
|
354
|
+
|
|
355
|
+
if set_up_packages:
|
|
356
|
+
logger.debug("Configuring %s with features %s", set_up_packages, features)
|
|
357
|
+
|
|
358
|
+
for i in set_up_packages:
|
|
359
|
+
__traceback_info__ = (i, self)
|
|
360
|
+
if isinstance(i, tuple):
|
|
361
|
+
filename = i[0]
|
|
362
|
+
package = i[1]
|
|
363
|
+
else:
|
|
364
|
+
filename = 'configure.zcml'
|
|
365
|
+
package = i
|
|
366
|
+
|
|
367
|
+
if isinstance(package, str):
|
|
368
|
+
package = dottedname.resolve(package)
|
|
369
|
+
|
|
370
|
+
try:
|
|
371
|
+
context = xmlconfig.file(filename, package=package, context=context)
|
|
372
|
+
except IOError as e:
|
|
373
|
+
# Did we pass in a test module (__name__) and there is no
|
|
374
|
+
# configuration in that package? In that case, we want to
|
|
375
|
+
# configure the parent package for sure
|
|
376
|
+
module_path = getattr(package, '__file__', '')
|
|
377
|
+
if (module_path
|
|
378
|
+
and 'tests' in module_path
|
|
379
|
+
and os.path.join(os.path.dirname(module_path), filename) == e.filename):
|
|
380
|
+
parent_package_name = '.'.join(package.__name__.split('.')[:-2])
|
|
381
|
+
package = dottedname.resolve(parent_package_name)
|
|
382
|
+
context = xmlconfig.file(filename, package=package, context=context)
|
|
383
|
+
else: # pragma: no cover
|
|
384
|
+
raise
|
|
385
|
+
|
|
386
|
+
return context
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
class ConfiguringTestBase(AbstractConfiguringObject,
|
|
390
|
+
AbstractTestBase):
|
|
391
|
+
"""
|
|
392
|
+
Test case that can be subclassed when ZCML configuration is desired.
|
|
393
|
+
|
|
394
|
+
Configuration is established by the class attributes documented
|
|
395
|
+
on :class:`AbstractConfiguringObject`.
|
|
396
|
+
|
|
397
|
+
.. note:: The ZCML configuration is executed for each test.
|
|
398
|
+
"""
|
|
399
|
+
|
|
400
|
+
def _doSetUpSuper(self):
|
|
401
|
+
super().setUp()
|
|
402
|
+
|
|
403
|
+
def setUp(self):
|
|
404
|
+
AbstractConfiguringObject._doSetUp(self)
|
|
405
|
+
|
|
406
|
+
#: Configure additional packages. This should only be done in the ``setUp`` method
|
|
407
|
+
#: of a subclass. Note that this is called by ``setUp``.
|
|
408
|
+
configure_packages = AbstractConfiguringObject._do_configure_packages
|
|
409
|
+
|
|
410
|
+
def configure_string(self, zcml_string):
|
|
411
|
+
"""
|
|
412
|
+
Execute the given ZCML string.
|
|
413
|
+
|
|
414
|
+
Tests may use this after ``setUp`` is called (this includes in the
|
|
415
|
+
implementation of your own ``setUp`` function).
|
|
416
|
+
"""
|
|
417
|
+
self.configuration_context = xmlconfig.string(zcml_string, self.configuration_context)
|
|
418
|
+
return self.configuration_context
|
|
419
|
+
|
|
420
|
+
def _doTearDownSuper(self):
|
|
421
|
+
super().tearDown()
|
|
422
|
+
|
|
423
|
+
def tearDown(self):
|
|
424
|
+
self._doTearDownConfiguration()
|
|
425
|
+
|
|
426
|
+
def _doTearDownConfiguration(self):
|
|
427
|
+
"""
|
|
428
|
+
Hook for subclasses to override.
|
|
429
|
+
|
|
430
|
+
This implementation calls :meth:`AbstractConfiguringObject._doTearDown`
|
|
431
|
+
with the default parameters. If you need to call it with a different
|
|
432
|
+
set of parameters, override this method to do so.
|
|
433
|
+
|
|
434
|
+
This method takes no arguments because the arguments passed to
|
|
435
|
+
``_doTearDown`` are almost always static at the callsite.
|
|
436
|
+
"""
|
|
437
|
+
AbstractConfiguringObject._doTearDown(
|
|
438
|
+
self,
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
class SharedConfiguringTestBase(AbstractConfiguringObject,
|
|
442
|
+
AbstractSharedTestBase):
|
|
443
|
+
"""
|
|
444
|
+
Test case that can be subclassed when ZCML configuration is desired.
|
|
445
|
+
|
|
446
|
+
Configuration is established by the class attributes documented on
|
|
447
|
+
:class:`AbstractConfiguringObject`. (The ``configuration_context`` is also
|
|
448
|
+
a class attribute.)
|
|
449
|
+
|
|
450
|
+
.. note:: The ZCML configuration is only executed once, before
|
|
451
|
+
any tests are run.
|
|
452
|
+
"""
|
|
453
|
+
|
|
454
|
+
@classmethod
|
|
455
|
+
def _doSetUpSuper(cls):
|
|
456
|
+
super(SharedConfiguringTestBase, cls).setUpClass()
|
|
457
|
+
|
|
458
|
+
setUpClass = classmethod(AbstractConfiguringObject._doSetUp)
|
|
459
|
+
|
|
460
|
+
#: Configure additional packages. This should only be done in the ``setUpClass``
|
|
461
|
+
#: method of a subclass after calling the super class. Note that this is called by
|
|
462
|
+
#: ``setUpClass``.
|
|
463
|
+
configure_packages = classmethod(AbstractConfiguringObject._do_configure_packages)
|
|
464
|
+
|
|
465
|
+
#: .. seealso:: :meth:`~.AbstractConfiguringObject.get_configuration_package_for_class`
|
|
466
|
+
#: .. versionadded:: 2.1.0
|
|
467
|
+
get_configuration_package = classmethod(
|
|
468
|
+
AbstractConfiguringObject.get_configuration_package_for_class
|
|
469
|
+
)
|
|
470
|
+
|
|
471
|
+
@classmethod
|
|
472
|
+
def _doTearDownSuper(cls):
|
|
473
|
+
super(SharedConfiguringTestBase, cls).tearDownClass()
|
|
474
|
+
|
|
475
|
+
tearDownClass = classmethod(AbstractConfiguringObject._doTearDown)
|
|
476
|
+
|
|
477
|
+
def tearDown(self):
|
|
478
|
+
AbstractConfiguringObject._doTearDown(
|
|
479
|
+
self,
|
|
480
|
+
clear_configuration_context=False,
|
|
481
|
+
super_tear_down=super().tearDown)
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
def module_setup(set_up_packages=(),
|
|
485
|
+
features=('devmode', 'testmode'),
|
|
486
|
+
configure_events=True):
|
|
487
|
+
"""
|
|
488
|
+
A module-level fixture for configuring packages.
|
|
489
|
+
|
|
490
|
+
Either import this as ``setUpModule`` at the module level, or call
|
|
491
|
+
it to perform module level set up from your own function with that name.
|
|
492
|
+
If you use this, you must also use :func:`module_teardown`.
|
|
493
|
+
|
|
494
|
+
This is an alternative to using :class:`ConfiguringTestBase`; the
|
|
495
|
+
two should generally not be mixed in a module. It can also be used
|
|
496
|
+
with Nose's `with_setup` function.
|
|
497
|
+
"""
|
|
498
|
+
zope.testing.cleanup.setUp()
|
|
499
|
+
setHooks()
|
|
500
|
+
if configure_events:
|
|
501
|
+
if set_up_packages:
|
|
502
|
+
component.provideHandler(eventtesting.events.append, (None,))
|
|
503
|
+
else:
|
|
504
|
+
eventtesting.setUp()
|
|
505
|
+
|
|
506
|
+
_configure(set_up_packages=set_up_packages, features=features)
|
|
507
|
+
|
|
508
|
+
def module_teardown():
|
|
509
|
+
"""
|
|
510
|
+
Tears down the module-level fixture for configuring packages
|
|
511
|
+
established by :func:`module_setup`.
|
|
512
|
+
|
|
513
|
+
Either import this as ``tearDownModule`` at the module level, or
|
|
514
|
+
call it to perform module level tear down froum your own function
|
|
515
|
+
with that name.
|
|
516
|
+
|
|
517
|
+
This is an alternative to using :class:`ConfiguringTestBase`; the
|
|
518
|
+
two should generally not be mixed in a module.
|
|
519
|
+
"""
|
|
520
|
+
eventtesting.clearEvents() # redundant with zope.testing.cleanup
|
|
521
|
+
# we never actually want to do this, it's not needed and can mess up other fixtures
|
|
522
|
+
# resetHooks()
|
|
523
|
+
zope.testing.cleanup.tearDown()
|
|
524
|
+
|
|
525
|
+
# The cleanup that we get by importing just zope.interface and
|
|
526
|
+
# zope.component has a problem: zope.component installs adapter hooks
|
|
527
|
+
# that cause the use of interfaces as functions to direct through the
|
|
528
|
+
# current site manager (as does the global component API). This
|
|
529
|
+
# adapter hook is a cached function of an implementation detail of the
|
|
530
|
+
# site manager: siteManager.adapters.adapter_hook.
|
|
531
|
+
#
|
|
532
|
+
# If no site is ever set, this caches the adapter_hook of the globalSiteManager.
|
|
533
|
+
#
|
|
534
|
+
# When the zope.component cleanup runs, it swizzles out the internals
|
|
535
|
+
# of the globalSiteManager by re-running __init__. However, it does
|
|
536
|
+
# not clear the cached adapter_hook. Thus, subsequent uses of the
|
|
537
|
+
# adapter hook (interface calls, or use of the global component API)
|
|
538
|
+
# continue to use the *old* adapter registry (which is no longer easy
|
|
539
|
+
# to access and inspect, especially when the C hook optimizations are
|
|
540
|
+
# in use) If any non-ZCML registrations are made (or the next test
|
|
541
|
+
# loads a subset of the ZCML the previous test did) then this
|
|
542
|
+
# manifests as strange adapter failures.
|
|
543
|
+
#
|
|
544
|
+
# This is obviously all implementation detail. So rather than "fix" the problem
|
|
545
|
+
# ourself, the solution is to import zope.site.site to ensure that the site gets
|
|
546
|
+
# cleaned up and the adapter_hook cache thrown away
|
|
547
|
+
# This problem never manifests itself in code that has already imported zope.site,
|
|
548
|
+
# and it seems to be an assumption that code that uses zope.component also uses zope.site
|
|
549
|
+
# (though we have some code that doesn't explicitly do so)
|
|
550
|
+
|
|
551
|
+
# This is detailed in test_component_broken.txt
|
|
552
|
+
# submitted as https://bugs.launchpad.net/zope.component/+bug/1100501
|
|
553
|
+
# transferred to github as https://github.com/zopefoundation/zope.component/pull/1
|
|
554
|
+
#import zope.site.site
|
|
555
|
+
# This is identified as fixed in zope.component 4.2.0
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
# Zope.mimetype registers hundreds and thousands of objects
|
|
559
|
+
# doing that for each test makes them take SO much longer
|
|
560
|
+
# Unfortunately, as noted above, zope.testing.cleanup.CleanUp
|
|
561
|
+
# installs something to reset the gsm, so it's not possible
|
|
562
|
+
# to simply pre-cache like the below:
|
|
563
|
+
# try:
|
|
564
|
+
# import zope.mimetype
|
|
565
|
+
# _configure(None, (('meta.zcml',zope.mimetype),
|
|
566
|
+
# ('meta.zcml',zope.component),
|
|
567
|
+
# zope.mimetype))
|
|
568
|
+
# except ImportError:
|
|
569
|
+
# pass
|
|
570
|
+
|
|
571
|
+
# Attempting to runaround the testing cleanup by
|
|
572
|
+
# using a different base doesn't quite work,
|
|
573
|
+
# some things are still using the old one
|
|
574
|
+
# globalregistry.base = BaseComponents()
|