diff options
| author | Chris McDonough <chrism@agendaless.com> | 2009-12-17 16:00:02 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2009-12-17 16:00:02 +0000 |
| commit | bc857e7e6e71a4001f03c608a18bac7dab36ccff (patch) | |
| tree | a34b0b761a92791bb60b2fbfafabe79e4a675682 /repoze/bfg/tests | |
| parent | 9d73300fcef0c0cd4af9c439a900d15fa4651914 (diff) | |
| download | pyramid-bc857e7e6e71a4001f03c608a18bac7dab36ccff.tar.gz pyramid-bc857e7e6e71a4001f03c608a18bac7dab36ccff.tar.bz2 pyramid-bc857e7e6e71a4001f03c608a18bac7dab36ccff.zip | |
Features
--------
- The ``Configurator`` object now has two new methods: ``begin`` and
``end``. The ``begin`` method is meant to be called before any
"configuration" begins (e.g. before ``add_view``, et. al are
called). The ``end`` method is meant to be called after all
"configuration" is complete.
Previously, before there was imperative configuration at all (1.1
and prior), configuration begin and end was invariably implied by
the process of loading a ZCML file. When a ZCML load happened, the
threadlocal data structure containing the request and registry was
modified before the load, and torn down after the load, making sure
that all framework code that needed ``get_current_registry`` for the
duration of the ZCML load was satisfied.
Some API methods called during imperative configuration, (such as
``Configurator.add_view`` when a renderer is involved) end up for
historical reasons calling ``get_current_registry``. However, in
1.2a5 and below, the Configurator supplied no functionality that
allowed people to make sure that ``get_current_registry`` returned
the registry implied by the configurator being used. ``begin`` now
serves this purpose. Inversely, ``end`` pops the thread local
stack, undoing the actions of ``begin``.
We make this boundary explicit to reduce the potential for confusion
when the configurator is used in different circumstances (e.g. in
unit tests and app code vs. just in initial app setup).
Existing code written for 1.2a1-1.2a5 which does not call ``begin``
or ``end`` continues to work in the same manner it did before. It
is however suggested that this code be changed to call ``begin`` and
``end`` to reduce the potential for confusion in the future.
- All ``paster`` templates which generate an application skeleton now
make use of the new ``begin`` and ``end`` methods of the
Configurator they use in their respective copies of ``run.py`` and
``tests.py``.
Documentation
-------------
- All documentation that makes use of a ``Configurator`` object to do
application setup and test setup now makes use of the new ``begin``
and ``end`` methods of the configurator.
Bug Fixes
---------
- When a ``repoze.bfg.exceptions.NotFound`` or
``repoze.bfg.exceptions.Forbidden`` *class* (as opposed to instance)
was raised as an exception within a root factory (or route root
factory), the exception would not be caught properly by the
``repoze.bfg.`` Router and it would propagate to up the call stack,
as opposed to rendering the not found view or the forbidden view as
would have been expected.
Diffstat (limited to 'repoze/bfg/tests')
| -rw-r--r-- | repoze/bfg/tests/fixtureapp/views.py | 3 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_configuration.py | 54 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_integration.py | 2 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_router.py | 56 |
4 files changed, 103 insertions, 12 deletions
diff --git a/repoze/bfg/tests/fixtureapp/views.py b/repoze/bfg/tests/fixtureapp/views.py index 82e92d618..d9bc0bb6e 100644 --- a/repoze/bfg/tests/fixtureapp/views.py +++ b/repoze/bfg/tests/fixtureapp/views.py @@ -5,9 +5,6 @@ def fixture_view(context, request): """ """ return Response('fixture') -def renderer_view(request): - return {'a':1} - class IDummy(Interface): pass diff --git a/repoze/bfg/tests/test_configuration.py b/repoze/bfg/tests/test_configuration.py index 2e2283ab4..a42e230f1 100644 --- a/repoze/bfg/tests/test_configuration.py +++ b/repoze/bfg/tests/test_configuration.py @@ -88,6 +88,36 @@ class ConfiguratorTests(unittest.TestCase): self.failUnless(config.registry.getUtility(IRendererFactory, '.pt')) self.failUnless(config.registry.getUtility(IRendererFactory, '.txt')) + def test_begin(self): + from repoze.bfg.configuration import Configurator + config = Configurator() + manager = DummyThreadLocalManager() + config.manager = manager + config.begin() + self.assertEqual(manager.pushed, + {'registry':config.registry, 'request':None}) + self.assertEqual(manager.popped, False) + + def test_begin_with_request(self): + from repoze.bfg.configuration import Configurator + config = Configurator() + request = object() + manager = DummyThreadLocalManager() + config.manager = manager + config.begin(request=request) + self.assertEqual(manager.pushed, + {'registry':config.registry, 'request':request}) + self.assertEqual(manager.popped, False) + + def test_end(self): + from repoze.bfg.configuration import Configurator + config = Configurator() + manager = DummyThreadLocalManager() + config.manager = manager + config.end() + self.assertEqual(manager.pushed, None) + self.assertEqual(manager.popped, True) + def test_ctor_with_package_registry(self): import sys from repoze.bfg.configuration import Configurator @@ -274,16 +304,12 @@ class ConfiguratorTests(unittest.TestCase): def test_make_wsgi_app(self): from repoze.bfg.router import Router from repoze.bfg.interfaces import IWSGIApplicationCreatedEvent - class ThreadLocalManager(object): - def push(self, d): - self.pushed = d - def pop(self): - self.popped = True - manager = ThreadLocalManager() + manager = DummyThreadLocalManager() config = self._makeOne() subscriber = self._registerEventListener(config, IWSGIApplicationCreatedEvent) - app = config.make_wsgi_app(manager=manager) + config.manager = manager + app = config.make_wsgi_app() self.assertEqual(app.__class__, Router) self.assertEqual(manager.pushed['registry'], config.registry) self.assertEqual(manager.pushed['request'], None) @@ -2702,6 +2728,12 @@ class DummyConfigurator(object): self.package = package self.settings = settings + def begin(self): + self.begun = True + + def end(self): + self.ended = True + def load_zcml(self, filename): self.zcml_file = filename @@ -2738,5 +2770,11 @@ class DummyMultiView: class DummyGetSiteManager(object): def sethook(self, hook): self.hook = hook - +class DummyThreadLocalManager(object): + pushed = None + popped = False + def push(self, d): + self.pushed = d + def pop(self): + self.popped = True diff --git a/repoze/bfg/tests/test_integration.py b/repoze/bfg/tests/test_integration.py index d210030af..da866f8d0 100644 --- a/repoze/bfg/tests/test_integration.py +++ b/repoze/bfg/tests/test_integration.py @@ -70,7 +70,7 @@ class TestFixtureApp(unittest.TestCase): config = Configurator() config.load_zcml('repoze.bfg.tests.fixtureapp:configure.zcml') twill.add_wsgi_intercept('localhost', 6543, config.make_wsgi_app) - if sys.platform is 'win32': + if sys.platform is 'win32': # pragma: no cover out = open('nul:', 'wb') else: out = open('/dev/null', 'wb') diff --git a/repoze/bfg/tests/test_router.py b/repoze/bfg/tests/test_router.py index 5352c6d79..c1d60ae9a 100644 --- a/repoze/bfg/tests/test_router.py +++ b/repoze/bfg/tests/test_router.py @@ -158,6 +158,62 @@ class TestRouter(unittest.TestCase): self.failIf('debug_notfound' in result[0]) self.assertEqual(len(logger.messages), 0) + def test_traverser_raises_notfound_class(self): + from repoze.bfg.exceptions import NotFound + environ = self._makeEnviron() + context = DummyContext() + self._registerTraverserFactory(context, raise_error=NotFound) + router = self._makeOne() + start_response = DummyStartResponse() + result = router(environ, start_response) + headers = start_response.headers + self.assertEqual(len(headers), 2) + status = start_response.status + self.assertEqual(status, '404 Not Found') + self.failUnless('<code></code>' in result[0], result) + + def test_traverser_raises_notfound_instance(self): + from repoze.bfg.exceptions import NotFound + environ = self._makeEnviron() + context = DummyContext() + self._registerTraverserFactory(context, raise_error=NotFound('foo')) + router = self._makeOne() + start_response = DummyStartResponse() + result = router(environ, start_response) + headers = start_response.headers + self.assertEqual(len(headers), 2) + status = start_response.status + self.assertEqual(status, '404 Not Found') + self.failUnless('<code>foo</code>' in result[0], result) + + def test_traverser_raises_forbidden_class(self): + from repoze.bfg.exceptions import Forbidden + environ = self._makeEnviron() + context = DummyContext() + self._registerTraverserFactory(context, raise_error=Forbidden) + router = self._makeOne() + start_response = DummyStartResponse() + result = router(environ, start_response) + headers = start_response.headers + self.assertEqual(len(headers), 2) + status = start_response.status + self.assertEqual(status, '401 Unauthorized') + self.failUnless('<code></code>' in result[0], result) + + def test_traverser_raises_forbidden_instance(self): + from repoze.bfg.exceptions import Forbidden + environ = self._makeEnviron() + context = DummyContext() + self._registerTraverserFactory(context, raise_error=Forbidden('foo')) + router = self._makeOne() + start_response = DummyStartResponse() + result = router(environ, start_response) + headers = start_response.headers + self.assertEqual(len(headers), 2) + status = start_response.status + self.assertEqual(status, '401 Unauthorized') + self.failUnless('<code>foo</code>' in result[0], result) + def test_call_no_view_registered_no_isettings(self): environ = self._makeEnviron() context = DummyContext() |
