Michael Merickel
2017-05-23 07e0e15fdafb28843a92cd03681a07aa652008a9
commit | author | age
5ed24b 1 import unittest
CM 2
b60bdb 3 from pyramid import testing
5ed24b 4
17b8bc 5 class TestRouter(unittest.TestCase):
5ed24b 6     def setUp(self):
32859f 7         self.config = testing.setUp()
CM 8         self.registry = self.config.registry
5ed24b 9
CM 10     def tearDown(self):
4de362 11         testing.tearDown()
5ed24b 12
cbfafb 13     def _registerRouteRequest(self, name):
b60bdb 14         from pyramid.interfaces import IRouteRequest
CM 15         from pyramid.request import route_request_iface
ff1213 16         iface = route_request_iface(name)
CM 17         self.registry.registerUtility(iface, IRouteRequest, name=name)
18         return iface
cbfafb 19
74409d 20     def _connectRoute(self, name, path, factory=None):
b60bdb 21         from pyramid.interfaces import IRoutesMapper
CM 22         from pyramid.urldispatch import RoutesMapper
4de362 23         mapper = self.registry.queryUtility(IRoutesMapper)
cbfafb 24         if mapper is None:
CM 25             mapper = RoutesMapper()
4de362 26             self.registry.registerUtility(mapper, IRoutesMapper)
0ccdc2 27         return mapper.connect(name, path, factory)
cbfafb 28
17ce57 29     def _registerLogger(self):
b60bdb 30         from pyramid.interfaces import IDebugLogger
a1a9fb 31         logger = DummyLogger()
bd39b1 32         self.registry.registerUtility(logger, IDebugLogger)
17ce57 33         return logger
CM 34
35     def _registerSettings(self, **kw):
831e70 36         settings = {'debug_authorization':False,
JK 37                     'debug_notfound':False,
24bf2a 38                     'debug_routematch':False}
37369c 39         settings.update(kw)
5a972b 40         self.registry.settings = settings
a1a9fb 41
0a0ffe 42     def _registerTraverserFactory(self, context, view_name='', subpath=None,
916f88 43                                   traversed=None, virtual_root=None,
29f5c1 44                                   virtual_root_path=None, raise_error=None,
CM 45                                   **kw):
b60bdb 46         from pyramid.interfaces import ITraverser
916f88 47
CM 48         if virtual_root is None:
49             virtual_root = context
50         if subpath is None:
51             subpath = []
52         if traversed is None:
53             traversed = []
54         if virtual_root_path is None:
55             virtual_root_path = []
56
57         class DummyTraverserFactory:
0a0ffe 58             def __init__(self, root):
916f88 59                 self.root = root
CM 60
acc776 61             def __call__(self, request):
29f5c1 62                 if raise_error:
CM 63                     raise raise_error
916f88 64                 values = {'root':self.root,
CM 65                           'context':context,
66                           'view_name':view_name,
67                           'subpath':subpath,
68                           'traversed':traversed,
69                           'virtual_root':virtual_root,
70                           'virtual_root_path':virtual_root_path}
71                 kw.update(values)
72                 return kw
077c3c 73
916f88 74         self.registry.registerAdapter(DummyTraverserFactory, (None,),
077c3c 75                                       ITraverser, name='')
7de404 76
ff1213 77     def _registerView(self, app, name, classifier, req_iface, ctx_iface):
b60bdb 78         from pyramid.interfaces import IView
ff1213 79         self.registry.registerAdapter(
CM 80             app, (classifier, req_iface, ctx_iface), IView, name)
7de404 81
c8cf22 82     def _registerEventListener(self, iface):
CM 83         L = []
84         def listener(event):
85             L.append(event)
971537 86         self.registry.registerHandler(listener, (iface,))
c8cf22 87         return L
a0423a 88
a1a9fb 89     def _registerRootFactory(self, val):
1eb861 90         rootfactory = DummyRootFactory(val)
b60bdb 91         from pyramid.interfaces import IRootFactory
a1a9fb 92         self.registry.registerUtility(rootfactory, IRootFactory)
CM 93         return rootfactory
358dc2 94
5ed24b 95     def _getTargetClass(self):
b60bdb 96         from pyramid.router import Router
5ed24b 97         return Router
CM 98
971537 99     def _makeOne(self):
5ed24b 100         klass = self._getTargetClass()
971537 101         return klass(self.registry)
5ed24b 102
799575 103     def _makeEnviron(self, **extras):
CM 104         environ = {
105             'wsgi.url_scheme':'http',
106             'SERVER_NAME':'localhost',
107             'SERVER_PORT':'8080',
108             'REQUEST_METHOD':'GET',
916f88 109             'PATH_INFO':'/',
799575 110             }
CM 111         environ.update(extras)
112         return environ
113
216f41 114     def test_ctor_registry_has_no_settings(self):
CM 115         self.registry.settings = None
116         router = self._makeOne()
74f9ae 117         self.assertEqual(router.debug_notfound, False)
CM 118         self.assertEqual(router.debug_routematch, False)
a1d395 119         self.assertFalse('debug_notfound' in router.__dict__)
CM 120         self.assertFalse('debug_routematch' in router.__dict__)
216f41 121
7cd5d4 122     def test_root_policy(self):
CM 123         context = DummyContext()
916f88 124         self._registerTraverserFactory(context)
dfc2b6 125         rootfactory = self._registerRootFactory('abc')
971537 126         router = self._makeOne()
7cd5d4 127         self.assertEqual(router.root_policy, rootfactory)
CM 128
81a833 129     def test_request_factory(self):
b60bdb 130         from pyramid.interfaces import IRequestFactory
81a833 131         class DummyRequestFactory(object):
CM 132             pass
133         self.registry.registerUtility(DummyRequestFactory, IRequestFactory)
134         router = self._makeOne()
135         self.assertEqual(router.request_factory, DummyRequestFactory)
136
b4843b 137     def test_tween_factories(self):
CM 138         from pyramid.interfaces import ITweens
5bf23f 139         from pyramid.config.tweens import Tweens
b4843b 140         from pyramid.response import Response
CM 141         from pyramid.interfaces import IViewClassifier
142         from pyramid.interfaces import IResponse
143         tweens = Tweens()
144         self.registry.registerUtility(tweens, ITweens)
28b404 145         L = []
b4843b 146         def tween_factory1(handler, registry):
28b404 147             L.append((handler, registry))
CM 148             def wrapper(request):
149                 request.environ['handled'].append('one')
150                 return handler(request)
151             wrapper.name = 'one'
152             wrapper.child = handler
153             return wrapper
b4843b 154         def tween_factory2(handler, registry):
28b404 155             L.append((handler, registry))
CM 156             def wrapper(request):
157                 request.environ['handled'] = ['two']
158                 return handler(request)
159             wrapper.name = 'two'
160             wrapper.child = handler
161             return wrapper
8517d4 162         tweens.add_implicit('one', tween_factory1)
CM 163         tweens.add_implicit('two', tween_factory2)
28b404 164         router = self._makeOne()
CM 165         self.assertEqual(router.handle_request.name, 'two')
166         self.assertEqual(router.handle_request.child.name, 'one')
167         self.assertEqual(router.handle_request.child.child.__name__,
168                          'handle_request')
169         context = DummyContext()
170         self._registerTraverserFactory(context)
171         environ = self._makeEnviron()
172         view = DummyView('abc')
173         self._registerView(self.config.derive_view(view), '',
174                            IViewClassifier, None, None)
175         start_response = DummyStartResponse()
176         def make_response(s):
177             return Response(s)
178         router.registry.registerAdapter(make_response, (str,), IResponse)
179         app_iter = router(environ, start_response)
8e606d 180         self.assertEqual(app_iter, [b'abc'])
28b404 181         self.assertEqual(start_response.status, '200 OK')
CM 182         self.assertEqual(environ['handled'], ['two', 'one'])
dc45ab 183
160f01 184     def test_call_traverser_default(self):
99edc5 185         from pyramid.httpexceptions import HTTPNotFound
160f01 186         environ = self._makeEnviron()
CM 187         logger = self._registerLogger()
188         router = self._makeOne()
189         start_response = DummyStartResponse()
a7e625 190         why = exc_raised(HTTPNotFound, router, environ, start_response)
478442 191         self.assertTrue('/' in why.args[0], why)
CM 192         self.assertFalse('debug_notfound' in why.args[0])
160f01 193         self.assertEqual(len(logger.messages), 0)
0d13f6 194
bc857e 195     def test_traverser_raises_notfound_class(self):
99edc5 196         from pyramid.httpexceptions import HTTPNotFound
bc857e 197         environ = self._makeEnviron()
CM 198         context = DummyContext()
a7e625 199         self._registerTraverserFactory(context, raise_error=HTTPNotFound)
bc857e 200         router = self._makeOne()
CM 201         start_response = DummyStartResponse()
a7e625 202         self.assertRaises(HTTPNotFound, router, environ, start_response)
bc857e 203
CM 204     def test_traverser_raises_notfound_instance(self):
99edc5 205         from pyramid.httpexceptions import HTTPNotFound
bc857e 206         environ = self._makeEnviron()
CM 207         context = DummyContext()
a7e625 208         self._registerTraverserFactory(context, raise_error=HTTPNotFound('foo'))
bc857e 209         router = self._makeOne()
CM 210         start_response = DummyStartResponse()
a7e625 211         why = exc_raised(HTTPNotFound, router, environ, start_response)
478442 212         self.assertTrue('foo' in why.args[0], why)
bc857e 213
CM 214     def test_traverser_raises_forbidden_class(self):
99edc5 215         from pyramid.httpexceptions import HTTPForbidden
bc857e 216         environ = self._makeEnviron()
CM 217         context = DummyContext()
99edc5 218         self._registerTraverserFactory(context, raise_error=HTTPForbidden)
bc857e 219         router = self._makeOne()
CM 220         start_response = DummyStartResponse()
99edc5 221         self.assertRaises(HTTPForbidden, router, environ, start_response)
bc857e 222
CM 223     def test_traverser_raises_forbidden_instance(self):
99edc5 224         from pyramid.httpexceptions import HTTPForbidden
bc857e 225         environ = self._makeEnviron()
CM 226         context = DummyContext()
99edc5 227         self._registerTraverserFactory(context,
CM 228                                        raise_error=HTTPForbidden('foo'))
bc857e 229         router = self._makeOne()
CM 230         start_response = DummyStartResponse()
99edc5 231         why = exc_raised(HTTPForbidden, router, environ, start_response)
478442 232         self.assertTrue('foo' in why.args[0], why)
bc857e 233
17ce57 234     def test_call_no_view_registered_no_isettings(self):
99edc5 235         from pyramid.httpexceptions import HTTPNotFound
799575 236         environ = self._makeEnviron()
7de404 237         context = DummyContext()
916f88 238         self._registerTraverserFactory(context)
17ce57 239         logger = self._registerLogger()
971537 240         router = self._makeOne()
7de404 241         start_response = DummyStartResponse()
a7e625 242         why = exc_raised(HTTPNotFound, router, environ, start_response)
478442 243         self.assertTrue('/' in why.args[0], why)
CM 244         self.assertFalse('debug_notfound' in why.args[0])
17ce57 245         self.assertEqual(len(logger.messages), 0)
CM 246
247     def test_call_no_view_registered_debug_notfound_false(self):
99edc5 248         from pyramid.httpexceptions import HTTPNotFound
17ce57 249         environ = self._makeEnviron()
CM 250         context = DummyContext()
916f88 251         self._registerTraverserFactory(context)
17ce57 252         logger = self._registerLogger()
CM 253         self._registerSettings(debug_notfound=False)
971537 254         router = self._makeOne()
17ce57 255         start_response = DummyStartResponse()
a7e625 256         why = exc_raised(HTTPNotFound, router, environ, start_response)
478442 257         self.assertTrue('/' in why.args[0], why)
CM 258         self.assertFalse('debug_notfound' in why.args[0])
17ce57 259         self.assertEqual(len(logger.messages), 0)
CM 260
261     def test_call_no_view_registered_debug_notfound_true(self):
99edc5 262         from pyramid.httpexceptions import HTTPNotFound
17ce57 263         environ = self._makeEnviron()
CM 264         context = DummyContext()
916f88 265         self._registerTraverserFactory(context)
17ce57 266         self._registerSettings(debug_notfound=True)
CM 267         logger = self._registerLogger()
971537 268         router = self._makeOne()
17ce57 269         start_response = DummyStartResponse()
a7e625 270         why = exc_raised(HTTPNotFound, router, environ, start_response)
a1d395 271         self.assertTrue(
7950a2 272             "debug_notfound of url http://localhost:8080/; " in why.args[0])
478442 273         self.assertTrue("view_name: '', subpath: []" in why.args[0])
CM 274         self.assertTrue('http://localhost:8080' in why.args[0], why)
ff1213 275
17ce57 276         self.assertEqual(len(logger.messages), 1)
CM 277         message = logger.messages[0]
a1d395 278         self.assertTrue('of url http://localhost:8080' in message)
7950a2 279         self.assertTrue("path_info: " in message)
478442 280         self.assertTrue('DummyContext' in message)
a1d395 281         self.assertTrue("view_name: ''" in message)
CM 282         self.assertTrue("subpath: []" in message)
5ed24b 283
d868ff 284     def test_call_view_returns_non_iresponse(self):
b60bdb 285         from pyramid.interfaces import IViewClassifier
7292d4 286         context = DummyContext()
916f88 287         self._registerTraverserFactory(context)
7292d4 288         environ = self._makeEnviron()
1eb861 289         view = DummyView('abc')
32859f 290         self._registerView(self.config.derive_view(view), '', IViewClassifier,
CM 291                            None, None)
b5f5b3 292         router = self._makeOne()
CM 293         start_response = DummyStartResponse()
294         self.assertRaises(ValueError, router, environ, start_response)
d868ff 295
CM 296     def test_call_view_returns_adapted_response(self):
297         from pyramid.response import Response
298         from pyramid.interfaces import IViewClassifier
299         from pyramid.interfaces import IResponse
300         context = DummyContext()
301         self._registerTraverserFactory(context)
302         environ = self._makeEnviron()
303         view = DummyView('abc')
32859f 304         self._registerView(self.config.derive_view(view), '',
CM 305                            IViewClassifier, None, None)
d868ff 306         router = self._makeOne()
CM 307         start_response = DummyStartResponse()
308         def make_response(s):
309             return Response(s)
310         router.registry.registerAdapter(make_response, (str,), IResponse)
311         app_iter = router(environ, start_response)
8e606d 312         self.assertEqual(app_iter, [b'abc'])
d868ff 313         self.assertEqual(start_response.status, '200 OK')
b5f5b3 314
735987 315     def test_call_with_request_extensions(self):
CM 316         from pyramid.interfaces import IViewClassifier
317         from pyramid.interfaces import IRequestExtensions
318         from pyramid.interfaces import IRequest
319         from pyramid.request import Request
04cc91 320         from pyramid.util import InstancePropertyHelper
735987 321         context = DummyContext()
CM 322         self._registerTraverserFactory(context)
323         class Extensions(object):
324             def __init__(self):
325                 self.methods = {}
326                 self.descriptors = {}
327         extensions = Extensions()
04cc91 328         ext_method = lambda r: 'bar'
MM 329         name, fn = InstancePropertyHelper.make_property(ext_method, name='foo')
330         extensions.descriptors[name] = fn
735987 331         request = Request.blank('/')
CM 332         request.request_iface = IRequest
333         request.registry = self.registry
334         def request_factory(environ):
335             return request
336         self.registry.registerUtility(extensions, IRequestExtensions)
337         environ = self._makeEnviron()
338         response = DummyResponse()
339         response.app_iter = ['Hello world']
340         view = DummyView(response)
341         self._registerView(self.config.derive_view(view), '',
342                            IViewClassifier, None, None)
343         router = self._makeOne()
344         router.request_factory = request_factory
345         start_response = DummyStartResponse()
346         router(environ, start_response)
04cc91 347         self.assertEqual(view.request.foo, 'bar')
735987 348
7de404 349     def test_call_view_registered_nonspecific_default_path(self):
b60bdb 350         from pyramid.interfaces import IViewClassifier
5ed24b 351         context = DummyContext()
916f88 352         self._registerTraverserFactory(context)
7de404 353         response = DummyResponse()
4df575 354         response.app_iter = ['Hello world']
1eb861 355         view = DummyView(response)
799575 356         environ = self._makeEnviron()
32859f 357         self._registerView(self.config.derive_view(view), '',
CM 358                            IViewClassifier, None, None)
9a038d 359         self._registerRootFactory(context)
971537 360         router = self._makeOne()
7de404 361         start_response = DummyStartResponse()
5ed24b 362         result = router(environ, start_response)
7de404 363         self.assertEqual(result, ['Hello world'])
CM 364         self.assertEqual(start_response.headers, ())
365         self.assertEqual(start_response.status, '200 OK')
164677 366         request = view.request
CM 367         self.assertEqual(request.view_name, '')
368         self.assertEqual(request.subpath, [])
369         self.assertEqual(request.context, context)
370         self.assertEqual(request.root, context)
5ed24b 371
916f88 372     def test_call_view_registered_nonspecific_nondefault_path_and_subpath(self):
b60bdb 373         from pyramid.interfaces import IViewClassifier
916f88 374         context = DummyContext()
CM 375         self._registerTraverserFactory(context, view_name='foo',
376                                        subpath=['bar'],
377                                        traversed=['context'])
9a038d 378         self._registerRootFactory(context)
916f88 379         response = DummyResponse()
CM 380         response.app_iter = ['Hello world']
1eb861 381         view = DummyView(response)
916f88 382         environ = self._makeEnviron()
ff1213 383         self._registerView(view, 'foo', IViewClassifier, None, None)
971537 384         router = self._makeOne()
7de404 385         start_response = DummyStartResponse()
5ed24b 386         result = router(environ, start_response)
7de404 387         self.assertEqual(result, ['Hello world'])
CM 388         self.assertEqual(start_response.headers, ())
389         self.assertEqual(start_response.status, '200 OK')
164677 390         request = view.request
CM 391         self.assertEqual(request.view_name, 'foo')
392         self.assertEqual(request.subpath, ['bar'])
393         self.assertEqual(request.context, context)
394         self.assertEqual(request.root, context)
799575 395
7de404 396     def test_call_view_registered_specific_success(self):
799575 397         from zope.interface import Interface
CM 398         from zope.interface import directlyProvides
399         class IContext(Interface):
400             pass
b60bdb 401         from pyramid.interfaces import IRequest
CM 402         from pyramid.interfaces import IViewClassifier
799575 403         context = DummyContext()
7de404 404         directlyProvides(context, IContext)
916f88 405         self._registerTraverserFactory(context)
9a038d 406         self._registerRootFactory(context)
7de404 407         response = DummyResponse()
4df575 408         response.app_iter = ['Hello world']
1eb861 409         view = DummyView(response)
7de404 410         environ = self._makeEnviron()
ff1213 411         self._registerView(view, '', IViewClassifier, IRequest, IContext)
971537 412         router = self._makeOne()
7de404 413         start_response = DummyStartResponse()
CM 414         result = router(environ, start_response)
415         self.assertEqual(result, ['Hello world'])
416         self.assertEqual(start_response.headers, ())
417         self.assertEqual(start_response.status, '200 OK')
164677 418         request = view.request
CM 419         self.assertEqual(request.view_name, '')
420         self.assertEqual(request.subpath, [])
421         self.assertEqual(request.context, context)
422         self.assertEqual(request.root, context)
7de404 423
CM 424     def test_call_view_registered_specific_fail(self):
799575 425         from zope.interface import Interface
CM 426         from zope.interface import directlyProvides
99edc5 427         from pyramid.httpexceptions import HTTPNotFound
b60bdb 428         from pyramid.interfaces import IViewClassifier
7de404 429         class IContext(Interface):
CM 430             pass
799575 431         class INotContext(Interface):
CM 432             pass
b60bdb 433         from pyramid.interfaces import IRequest
7de404 434         context = DummyContext()
799575 435         directlyProvides(context, INotContext)
916f88 436         self._registerTraverserFactory(context, subpath=[''])
7de404 437         response = DummyResponse()
1eb861 438         view = DummyView(response)
799575 439         environ = self._makeEnviron()
ff1213 440         self._registerView(view, '', IViewClassifier, IRequest, IContext)
971537 441         router = self._makeOne()
7de404 442         start_response = DummyStartResponse()
a7e625 443         self.assertRaises(HTTPNotFound, router, environ, start_response)
111593 444
ef5149 445     def test_call_view_raises_forbidden(self):
2466f6 446         from zope.interface import Interface
CM 447         from zope.interface import directlyProvides
99edc5 448         from pyramid.httpexceptions import HTTPForbidden
2466f6 449         class IContext(Interface):
CM 450             pass
b60bdb 451         from pyramid.interfaces import IRequest
CM 452         from pyramid.interfaces import IViewClassifier
2466f6 453         context = DummyContext()
CM 454         directlyProvides(context, IContext)
916f88 455         self._registerTraverserFactory(context, subpath=[''])
2466f6 456         response = DummyResponse()
99edc5 457         view = DummyView(response,
CM 458                          raise_exception=HTTPForbidden("unauthorized"))
2466f6 459         environ = self._makeEnviron()
ff1213 460         self._registerView(view, '', IViewClassifier, IRequest, IContext)
971537 461         router = self._makeOne()
2466f6 462         start_response = DummyStartResponse()
99edc5 463         why = exc_raised(HTTPForbidden, router, environ, start_response)
478442 464         self.assertEqual(why.args[0], 'unauthorized')
2466f6 465
d66bfb 466     def test_call_view_raises_notfound(self):
17ce57 467         from zope.interface import Interface
CM 468         from zope.interface import directlyProvides
469         class IContext(Interface):
470             pass
b60bdb 471         from pyramid.interfaces import IRequest
CM 472         from pyramid.interfaces import IViewClassifier
99edc5 473         from pyramid.httpexceptions import HTTPNotFound
17ce57 474         context = DummyContext()
CM 475         directlyProvides(context, IContext)
916f88 476         self._registerTraverserFactory(context, subpath=[''])
17ce57 477         response = DummyResponse()
a7e625 478         view = DummyView(response, raise_exception=HTTPNotFound("notfound"))
17ce57 479         environ = self._makeEnviron()
ff1213 480         self._registerView(view, '', IViewClassifier, IRequest, IContext)
971537 481         router = self._makeOne()
17ce57 482         start_response = DummyStartResponse()
a7e625 483         why = exc_raised(HTTPNotFound, router, environ, start_response)
478442 484         self.assertEqual(why.args[0], 'notfound')
ef5149 485
d05117 486     def test_call_view_raises_response_cleared(self):
CM 487         from zope.interface import Interface
488         from zope.interface import directlyProvides
489         from pyramid.interfaces import IExceptionViewClassifier
490         class IContext(Interface):
491             pass
492         from pyramid.interfaces import IRequest
493         from pyramid.interfaces import IViewClassifier
494         context = DummyContext()
495         directlyProvides(context, IContext)
496         self._registerTraverserFactory(context, subpath=[''])
497         def view(context, request):
498             request.response.a = 1
499             raise KeyError
500         def exc_view(context, request):
a80206 501             self.assertFalse(hasattr(request.response, 'a'))
8e606d 502             request.response.body = b'OK'
d05117 503             return request.response
CM 504         environ = self._makeEnviron()
505         self._registerView(view, '', IViewClassifier, IRequest, IContext)
506         self._registerView(exc_view, '', IExceptionViewClassifier,
507                            IRequest, KeyError)
508         router = self._makeOne()
509         start_response = DummyStartResponse()
510         itera = router(environ, start_response)
8e606d 511         self.assertEqual(itera, [b'OK'])
d05117 512
844e98 513     def test_call_request_has_response_callbacks(self):
839ea0 514         from zope.interface import Interface
CM 515         from zope.interface import directlyProvides
516         class IContext(Interface):
517             pass
b60bdb 518         from pyramid.interfaces import IRequest
CM 519         from pyramid.interfaces import IViewClassifier
839ea0 520         context = DummyContext()
CM 521         directlyProvides(context, IContext)
522         self._registerTraverserFactory(context, subpath=[''])
523         response = DummyResponse('200 OK')
164677 524         def view(context, request):
844e98 525             def callback(request, response):
CM 526                 response.called_back = True
39a03e 527             request.add_response_callback(callback)
164677 528             return response
839ea0 529         environ = self._makeEnviron()
ff1213 530         self._registerView(view, '', IViewClassifier, IRequest, IContext)
839ea0 531         router = self._makeOne()
CM 532         start_response = DummyStartResponse()
164677 533         router(environ, start_response)
844e98 534         self.assertEqual(response.called_back, True)
839ea0 535
ad6a67 536     def test_call_request_has_finished_callbacks_when_view_succeeds(self):
CM 537         from zope.interface import Interface
538         from zope.interface import directlyProvides
539         class IContext(Interface):
540             pass
b60bdb 541         from pyramid.interfaces import IRequest
CM 542         from pyramid.interfaces import IViewClassifier
ad6a67 543         context = DummyContext()
CM 544         directlyProvides(context, IContext)
545         self._registerTraverserFactory(context, subpath=[''])
546         response = DummyResponse('200 OK')
547         def view(context, request):
548             def callback(request):
549                 request.environ['called_back'] = True
39a03e 550             request.add_finished_callback(callback)
ad6a67 551             return response
CM 552         environ = self._makeEnviron()
553         self._registerView(view, '', IViewClassifier, IRequest, IContext)
554         router = self._makeOne()
555         start_response = DummyStartResponse()
556         router(environ, start_response)
557         self.assertEqual(environ['called_back'], True)
558
559     def test_call_request_has_finished_callbacks_when_view_raises(self):
560         from zope.interface import Interface
561         from zope.interface import directlyProvides
562         class IContext(Interface):
563             pass
b60bdb 564         from pyramid.interfaces import IRequest
CM 565         from pyramid.interfaces import IViewClassifier
ad6a67 566         context = DummyContext()
CM 567         directlyProvides(context, IContext)
568         self._registerTraverserFactory(context, subpath=[''])
569         def view(context, request):
570             def callback(request):
571                 request.environ['called_back'] = True
39a03e 572             request.add_finished_callback(callback)
ad6a67 573             raise NotImplementedError
CM 574         environ = self._makeEnviron()
575         self._registerView(view, '', IViewClassifier, IRequest, IContext)
576         router = self._makeOne()
577         start_response = DummyStartResponse()
578         exc_raised(NotImplementedError, router, environ, start_response)
579         self.assertEqual(environ['called_back'], True)
df15ed 580
ad6a67 581     def test_call_request_factory_raises(self):
CM 582         # making sure finally doesnt barf when a request cannot be created
583         environ = self._makeEnviron()
584         router = self._makeOne()
585         def dummy_request_factory(environ):
586             raise NotImplementedError
587         router.request_factory = dummy_request_factory
588         start_response = DummyStartResponse()
589         exc_raised(NotImplementedError, router, environ, start_response)
590
a0423a 591     def test_call_eventsends(self):
b60bdb 592         from pyramid.interfaces import INewRequest
CM 593         from pyramid.interfaces import INewResponse
59428d 594         from pyramid.interfaces import IBeforeTraversal
b60bdb 595         from pyramid.interfaces import IContextFound
CM 596         from pyramid.interfaces import IViewClassifier
a0423a 597         context = DummyContext()
916f88 598         self._registerTraverserFactory(context)
a0423a 599         response = DummyResponse()
CM 600         response.app_iter = ['Hello world']
1eb861 601         view = DummyView(response)
a0423a 602         environ = self._makeEnviron()
ff1213 603         self._registerView(view, '', IViewClassifier, None, None)
c8cf22 604         request_events = self._registerEventListener(INewRequest)
59428d 605         beforetraversal_events = self._registerEventListener(IBeforeTraversal)
4fe3ef 606         context_found_events = self._registerEventListener(IContextFound)
c8cf22 607         response_events = self._registerEventListener(INewResponse)
971537 608         router = self._makeOne()
a0423a 609         start_response = DummyStartResponse()
CM 610         result = router(environ, start_response)
611         self.assertEqual(len(request_events), 1)
612         self.assertEqual(request_events[0].request.environ, environ)
59428d 613         self.assertEqual(len(beforetraversal_events), 1)
BJR 614         self.assertEqual(beforetraversal_events[0].request.environ, environ)
4fe3ef 615         self.assertEqual(len(context_found_events), 1)
MA 616         self.assertEqual(context_found_events[0].request.environ, environ)
617         self.assertEqual(context_found_events[0].request.context, context)
a0423a 618         self.assertEqual(len(response_events), 1)
CM 619         self.assertEqual(response_events[0].response, response)
4fe3ef 620         self.assertEqual(response_events[0].request.context, context)
9a038d 621         self.assertEqual(result, response.app_iter)
a0b40c 622
ba2ac1 623     def test_call_newrequest_evllist_exc_can_be_caught_by_exceptionview(self):
CM 624         from pyramid.interfaces import INewRequest
625         from pyramid.interfaces import IExceptionViewClassifier
626         from pyramid.interfaces import IRequest
627         context = DummyContext()
628         self._registerTraverserFactory(context)
629         environ = self._makeEnviron()
630         def listener(event):
631             raise KeyError
632         self.registry.registerHandler(listener, (INewRequest,))
633         exception_response = DummyResponse()
634         exception_response.app_iter = ["Hello, world"]
635         exception_view = DummyView(exception_response)
636         environ = self._makeEnviron()
637         self._registerView(exception_view, '', IExceptionViewClassifier,
638                            IRequest, KeyError)
639         router = self._makeOne()
640         start_response = DummyStartResponse()
641         result = router(environ, start_response)
642         self.assertEqual(result, exception_response.app_iter)
643
a1a9fb 644     def test_call_pushes_and_pops_threadlocal_manager(self):
b60bdb 645         from pyramid.interfaces import IViewClassifier
a1a9fb 646         context = DummyContext()
CM 647         self._registerTraverserFactory(context)
648         response = DummyResponse()
649         response.app_iter = ['Hello world']
1eb861 650         view = DummyView(response)
a1a9fb 651         environ = self._makeEnviron()
ff1213 652         self._registerView(view, '', IViewClassifier, None, None)
a1a9fb 653         router = self._makeOne()
CM 654         start_response = DummyStartResponse()
655         router.threadlocal_manager = DummyThreadLocalManager()
9a038d 656         router(environ, start_response)
a1a9fb 657         self.assertEqual(len(router.threadlocal_manager.pushed), 1)
CM 658         self.assertEqual(len(router.threadlocal_manager.popped), 1)
08ead7 659
cbfafb 660     def test_call_route_matches_and_has_factory(self):
b60bdb 661         from pyramid.interfaces import IViewClassifier
831e70 662         logger = self._registerLogger()
24bf2a 663         self._registerSettings(debug_routematch=True)
ff1213 664         self._registerRouteRequest('foo')
cbfafb 665         root = object()
CM 666         def factory(request):
667             return root
0ccdc2 668         route = self._connectRoute('foo', 'archives/:action/:article', factory)
CM 669         route.predicates = [DummyPredicate()]
cbfafb 670         context = DummyContext()
CM 671         self._registerTraverserFactory(context)
672         response = DummyResponse()
673         response.app_iter = ['Hello world']
674         view = DummyView(response)
675         environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
ff1213 676         self._registerView(view, '', IViewClassifier, None, None)
9a038d 677         self._registerRootFactory(context)
cbfafb 678         router = self._makeOne()
CM 679         start_response = DummyStartResponse()
680         result = router(environ, start_response)
681         self.assertEqual(result, ['Hello world'])
682         self.assertEqual(start_response.headers, ())
683         self.assertEqual(start_response.status, '200 OK')
684         request = view.request
685         self.assertEqual(request.view_name, '')
686         self.assertEqual(request.subpath, [])
687         self.assertEqual(request.context, context)
688         self.assertEqual(request.root, root)
81d3b5 689         matchdict = {'action':'action1', 'article':'article1'}
CM 690         self.assertEqual(request.matchdict, matchdict)
691         self.assertEqual(request.matched_route.name, 'foo')
831e70 692         self.assertEqual(len(logger.messages), 1)
a1d395 693         self.assertTrue(
89335f 694             logger.messages[0].startswith(
24bf2a 695             "route matched for url http://localhost:8080"
831e70 696             "/archives/action1/article1; "
24bf2a 697             "route_name: 'foo', "
0ccdc2 698             "path_info: ")
CM 699             )
700         self.assertTrue(
701             "predicates: 'predicate'" in logger.messages[0]
702             )
831e70 703
24bf2a 704     def test_call_route_match_miss_debug_routematch(self):
99edc5 705         from pyramid.httpexceptions import HTTPNotFound
24bf2a 706         logger = self._registerLogger()
CM 707         self._registerSettings(debug_routematch=True)
708         self._registerRouteRequest('foo')
709         self._connectRoute('foo', 'archives/:action/:article')
710         context = DummyContext()
711         self._registerTraverserFactory(context)
712         environ = self._makeEnviron(PATH_INFO='/wontmatch')
713         self._registerRootFactory(context)
714         router = self._makeOne()
715         start_response = DummyStartResponse()
a7e625 716         self.assertRaises(HTTPNotFound, router, environ, start_response)
24bf2a 717
CM 718         self.assertEqual(len(logger.messages), 1)
719         self.assertEqual(
720             logger.messages[0],
721             'no route matched for url http://localhost:8080/wontmatch')
722
cbfafb 723     def test_call_route_matches_doesnt_overwrite_subscriber_iface(self):
b60bdb 724         from pyramid.interfaces import INewRequest
CM 725         from pyramid.interfaces import IViewClassifier
cbfafb 726         from zope.interface import alsoProvides
CM 727         from zope.interface import Interface
ff1213 728         self._registerRouteRequest('foo')
cbfafb 729         class IFoo(Interface):
CM 730             pass
731         def listener(event):
732             alsoProvides(event.request, IFoo)
733         self.registry.registerHandler(listener, (INewRequest,))
734         root = object()
735         def factory(request):
736             return root
74409d 737         self._connectRoute('foo', 'archives/:action/:article', factory)
cbfafb 738         context = DummyContext()
CM 739         self._registerTraverserFactory(context)
740         response = DummyResponse()
741         response.app_iter = ['Hello world']
742         view = DummyView(response)
743         environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
ff1213 744         self._registerView(view, '', IViewClassifier, None, None)
9a038d 745         self._registerRootFactory(context)
cbfafb 746         router = self._makeOne()
CM 747         start_response = DummyStartResponse()
748         result = router(environ, start_response)
749         self.assertEqual(result, ['Hello world'])
750         self.assertEqual(start_response.headers, ())
751         self.assertEqual(start_response.status, '200 OK')
752         request = view.request
753         self.assertEqual(request.view_name, '')
754         self.assertEqual(request.subpath, [])
755         self.assertEqual(request.context, context)
756         self.assertEqual(request.root, root)
81d3b5 757         matchdict = {'action':'action1', 'article':'article1'}
CM 758         self.assertEqual(request.matchdict, matchdict)
759         self.assertEqual(request.matched_route.name, 'foo')
a1d395 760         self.assertTrue(IFoo.providedBy(request))
a1a9fb 761
29f5c1 762     def test_root_factory_raises_notfound(self):
b60bdb 763         from pyramid.interfaces import IRootFactory
99edc5 764         from pyramid.httpexceptions import HTTPNotFound
29f5c1 765         from zope.interface import Interface
CM 766         from zope.interface import directlyProvides
767         def rootfactory(request):
a7e625 768             raise HTTPNotFound('from root factory')
29f5c1 769         self.registry.registerUtility(rootfactory, IRootFactory)
CM 770         class IContext(Interface):
771             pass
772         context = DummyContext()
773         directlyProvides(context, IContext)
774         environ = self._makeEnviron()
775         router = self._makeOne()
776         start_response = DummyStartResponse()
a7e625 777         why = exc_raised(HTTPNotFound, router, environ, start_response)
478442 778         self.assertTrue('from root factory' in why.args[0])
29f5c1 779
CM 780     def test_root_factory_raises_forbidden(self):
b60bdb 781         from pyramid.interfaces import IRootFactory
99edc5 782         from pyramid.httpexceptions import HTTPForbidden
29f5c1 783         from zope.interface import Interface
CM 784         from zope.interface import directlyProvides
785         def rootfactory(request):
99edc5 786             raise HTTPForbidden('from root factory')
29f5c1 787         self.registry.registerUtility(rootfactory, IRootFactory)
CM 788         class IContext(Interface):
789             pass
790         context = DummyContext()
791         directlyProvides(context, IContext)
792         environ = self._makeEnviron()
793         router = self._makeOne()
794         start_response = DummyStartResponse()
99edc5 795         why = exc_raised(HTTPForbidden, router, environ, start_response)
478442 796         self.assertTrue('from root factory' in why.args[0])
ff1213 797
CM 798     def test_root_factory_exception_propagating(self):
b60bdb 799         from pyramid.interfaces import IRootFactory
ff1213 800         from zope.interface import Interface
CM 801         from zope.interface import directlyProvides
802         def rootfactory(request):
803             raise RuntimeError()
804         self.registry.registerUtility(rootfactory, IRootFactory)
805         class IContext(Interface):
806             pass
807         context = DummyContext()
808         directlyProvides(context, IContext)
809         environ = self._makeEnviron()
810         router = self._makeOne()
811         start_response = DummyStartResponse()
812         self.assertRaises(RuntimeError, router, environ, start_response)
813
814     def test_traverser_exception_propagating(self):
815         environ = self._makeEnviron()
816         context = DummyContext()
817         self._registerTraverserFactory(context, raise_error=RuntimeError())
818         router = self._makeOne()
819         start_response = DummyStartResponse()
820         self.assertRaises(RuntimeError, router, environ, start_response)
821
822     def test_call_view_exception_propagating(self):
823         from zope.interface import Interface
824         from zope.interface import directlyProvides
825         class IContext(Interface):
826             pass
b60bdb 827         from pyramid.interfaces import IRequest
CM 828         from pyramid.interfaces import IViewClassifier
829         from pyramid.interfaces import IRequestFactory
6456c2 830         from pyramid.interfaces import IExceptionViewClassifier
81d3b5 831         def rfactory(environ):
CM 832             return request
833         self.registry.registerUtility(rfactory, IRequestFactory)
b60bdb 834         from pyramid.request import Request
81d3b5 835         request = Request.blank('/')
ff1213 836         context = DummyContext()
CM 837         directlyProvides(context, IContext)
838         self._registerTraverserFactory(context, subpath=[''])
839         response = DummyResponse()
6456c2 840         response.app_iter = ['OK']
579a5f 841         error = RuntimeError()
CM 842         view = DummyView(response, raise_exception=error)
ff1213 843         environ = self._makeEnviron()
6456c2 844         def exception_view(context, request):
CM 845             self.assertEqual(request.exc_info[0], RuntimeError)
846             return response
ff1213 847         self._registerView(view, '', IViewClassifier, IRequest, IContext)
6456c2 848         self._registerView(exception_view, '', IExceptionViewClassifier,
CM 849                            IRequest, RuntimeError)
ff1213 850         router = self._makeOne()
CM 851         start_response = DummyStartResponse()
6456c2 852         result = router(environ, start_response)
CM 853         self.assertEqual(result, ['OK'])
579a5f 854         # exc_info and exception should still be around on the request after
CM 855         # the excview tween has run (see
856         # https://github.com/Pylons/pyramid/issues/1223)
857         self.assertEqual(request.exception, error)
858         self.assertEqual(request.exc_info[:2], (RuntimeError, error,))
95a379 859         
ff1213 860     def test_call_view_raises_exception_view(self):
b60bdb 861         from pyramid.interfaces import IViewClassifier
CM 862         from pyramid.interfaces import IExceptionViewClassifier
863         from pyramid.interfaces import IRequest
ff1213 864         response = DummyResponse()
CM 865         exception_response = DummyResponse()
866         exception_response.app_iter = ["Hello, world"]
867         view = DummyView(response, raise_exception=RuntimeError)
3e3fcd 868         def exception_view(context, request):
CM 869             self.assertEqual(request.exception.__class__, RuntimeError)
870             return exception_response
ff1213 871         environ = self._makeEnviron()
CM 872         self._registerView(view, '', IViewClassifier, IRequest, None)
873         self._registerView(exception_view, '', IExceptionViewClassifier,
874                            IRequest, RuntimeError)
875         router = self._makeOne()
876         start_response = DummyStartResponse()
877         result = router(environ, start_response)
878         self.assertEqual(result, ["Hello, world"])
879
880     def test_call_view_raises_super_exception_sub_exception_view(self):
b60bdb 881         from pyramid.interfaces import IViewClassifier
CM 882         from pyramid.interfaces import IExceptionViewClassifier
883         from pyramid.interfaces import IRequest
ff1213 884         class SuperException(Exception):
CM 885             pass
886         class SubException(SuperException):
887             pass
888         response = DummyResponse()
889         exception_response = DummyResponse()
890         exception_response.app_iter = ["Hello, world"]
891         view = DummyView(response, raise_exception=SuperException)
892         exception_view = DummyView(exception_response)
893         environ = self._makeEnviron()
894         self._registerView(view, '', IViewClassifier, IRequest, None)
895         self._registerView(exception_view, '', IExceptionViewClassifier,
896                            IRequest, SubException)
897         router = self._makeOne()
898         start_response = DummyStartResponse()
899         self.assertRaises(SuperException, router, environ, start_response)
900
901     def test_call_view_raises_sub_exception_super_exception_view(self):
b60bdb 902         from pyramid.interfaces import IViewClassifier
CM 903         from pyramid.interfaces import IExceptionViewClassifier
904         from pyramid.interfaces import IRequest
ff1213 905         class SuperException(Exception):
CM 906             pass
907         class SubException(SuperException):
908             pass
909         response = DummyResponse()
910         exception_response = DummyResponse()
911         exception_response.app_iter = ["Hello, world"]
912         view = DummyView(response, raise_exception=SubException)
913         exception_view = DummyView(exception_response)
914         environ = self._makeEnviron()
915         self._registerView(view, '', IViewClassifier, IRequest, None)
916         self._registerView(exception_view, '', IExceptionViewClassifier,
917                            IRequest, SuperException)
918         router = self._makeOne()
919         start_response = DummyStartResponse()
920         result = router(environ, start_response)
921         self.assertEqual(result, ["Hello, world"])
922
923     def test_call_view_raises_exception_another_exception_view(self):
b60bdb 924         from pyramid.interfaces import IViewClassifier
CM 925         from pyramid.interfaces import IExceptionViewClassifier
926         from pyramid.interfaces import IRequest
ff1213 927         class MyException(Exception):
CM 928             pass
929         class AnotherException(Exception):
930             pass
931         response = DummyResponse()
932         exception_response = DummyResponse()
933         exception_response.app_iter = ["Hello, world"]
934         view = DummyView(response, raise_exception=MyException)
935         exception_view = DummyView(exception_response)
936         environ = self._makeEnviron()
937         self._registerView(view, '', IViewClassifier, IRequest, None)
938         self._registerView(exception_view, '', IExceptionViewClassifier,
939                            IRequest, AnotherException)
940         router = self._makeOne()
941         start_response = DummyStartResponse()
942         self.assertRaises(MyException, router, environ, start_response)
943
944     def test_root_factory_raises_exception_view(self):
b60bdb 945         from pyramid.interfaces import IRootFactory
CM 946         from pyramid.interfaces import IRequest
947         from pyramid.interfaces import IExceptionViewClassifier
ff1213 948         def rootfactory(request):
CM 949             raise RuntimeError()
950         self.registry.registerUtility(rootfactory, IRootFactory)
951         exception_response = DummyResponse()
952         exception_response.app_iter = ["Hello, world"]
953         exception_view = DummyView(exception_response)
954         self._registerView(exception_view, '', IExceptionViewClassifier,
955                            IRequest, RuntimeError)
956         environ = self._makeEnviron()
957         router = self._makeOne()
958         start_response = DummyStartResponse()
29f5c1 959         app_iter = router(environ, start_response)
ff1213 960         self.assertEqual(app_iter, ["Hello, world"])
CM 961
962     def test_traverser_raises_exception_view(self):
b60bdb 963         from pyramid.interfaces import IRequest
CM 964         from pyramid.interfaces import IExceptionViewClassifier
ff1213 965         environ = self._makeEnviron()
CM 966         context = DummyContext()
967         self._registerTraverserFactory(context, raise_error=RuntimeError())
968         exception_response = DummyResponse()
969         exception_response.app_iter = ["Hello, world"]
970         exception_view = DummyView(exception_response)
971         self._registerView(exception_view, '', IExceptionViewClassifier,
972                            IRequest, RuntimeError)
973         router = self._makeOne()
974         start_response = DummyStartResponse()
975         result = router(environ, start_response)
976         self.assertEqual(result, ["Hello, world"])
977
d868ff 978     def test_exception_view_returns_non_iresponse(self):
b60bdb 979         from pyramid.interfaces import IRequest
CM 980         from pyramid.interfaces import IViewClassifier
981         from pyramid.interfaces import IExceptionViewClassifier
ff1213 982         environ = self._makeEnviron()
CM 983         response = DummyResponse()
984         view = DummyView(response, raise_exception=RuntimeError)
32859f 985         
CM 986         self._registerView(self.config.derive_view(view), '',
987                            IViewClassifier, IRequest, None)
ff1213 988         exception_view = DummyView(None)
32859f 989         self._registerView(self.config.derive_view(exception_view), '',
CM 990                            IExceptionViewClassifier,
ff1213 991                            IRequest, RuntimeError)
CM 992         router = self._makeOne()
993         start_response = DummyStartResponse()
994         self.assertRaises(ValueError, router, environ, start_response)
995
996     def test_call_route_raises_route_exception_view(self):
b60bdb 997         from pyramid.interfaces import IViewClassifier
CM 998         from pyramid.interfaces import IExceptionViewClassifier
ff1213 999         req_iface = self._registerRouteRequest('foo')
74409d 1000         self._connectRoute('foo', 'archives/:action/:article', None)
ff1213 1001         view = DummyView(DummyResponse(), raise_exception=RuntimeError)
CM 1002         self._registerView(view, '', IViewClassifier, req_iface, None)
1003         response = DummyResponse()
1004         response.app_iter = ["Hello, world"]
1005         exception_view = DummyView(response)
1006         self._registerView(exception_view, '', IExceptionViewClassifier,
1007                            req_iface, RuntimeError)
1008         environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
1009         start_response = DummyStartResponse()
1010         router = self._makeOne()
1011         result = router(environ, start_response)
1012         self.assertEqual(result, ["Hello, world"])
1013
1014     def test_call_view_raises_exception_route_view(self):
b60bdb 1015         from pyramid.interfaces import IViewClassifier
CM 1016         from pyramid.interfaces import IExceptionViewClassifier
1017         from pyramid.interfaces import IRequest
ff1213 1018         req_iface = self._registerRouteRequest('foo')
74409d 1019         self._connectRoute('foo', 'archives/:action/:article', None)
ff1213 1020         view = DummyView(DummyResponse(), raise_exception=RuntimeError)
CM 1021         self._registerView(view, '', IViewClassifier, IRequest, None)
1022         response = DummyResponse()
1023         response.app_iter = ["Hello, world"]
1024         exception_view = DummyView(response)
1025         self._registerView(exception_view, '', IExceptionViewClassifier,
1026                            req_iface, RuntimeError)
1027         environ = self._makeEnviron()
1028         start_response = DummyStartResponse()
1029         router = self._makeOne()
1030         self.assertRaises(RuntimeError, router, environ, start_response)
1031
1032     def test_call_route_raises_exception_view(self):
b60bdb 1033         from pyramid.interfaces import IViewClassifier
CM 1034         from pyramid.interfaces import IExceptionViewClassifier
1035         from pyramid.interfaces import IRequest
ff1213 1036         req_iface = self._registerRouteRequest('foo')
74409d 1037         self._connectRoute('foo', 'archives/:action/:article', None)
ff1213 1038         view = DummyView(DummyResponse(), raise_exception=RuntimeError)
CM 1039         self._registerView(view, '', IViewClassifier, req_iface, None)
1040         response = DummyResponse()
1041         response.app_iter = ["Hello, world"]
1042         exception_view = DummyView(response)
1043         self._registerView(exception_view, '', IExceptionViewClassifier,
1044                            IRequest, RuntimeError)
1045         environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
1046         start_response = DummyStartResponse()
1047         router = self._makeOne()
1048         result = router(environ, start_response)
1049         self.assertEqual(result, ["Hello, world"])
1050
1051     def test_call_route_raises_super_exception_sub_exception_view(self):
b60bdb 1052         from pyramid.interfaces import IViewClassifier
CM 1053         from pyramid.interfaces import IExceptionViewClassifier
1054         from pyramid.interfaces import IRequest
ff1213 1055         class SuperException(Exception):
CM 1056             pass
1057         class SubException(SuperException):
1058             pass
1059         req_iface = self._registerRouteRequest('foo')
74409d 1060         self._connectRoute('foo', 'archives/:action/:article', None)
ff1213 1061         view = DummyView(DummyResponse(), raise_exception=SuperException)
CM 1062         self._registerView(view, '', IViewClassifier, req_iface, None)
1063         response = DummyResponse()
1064         response.app_iter = ["Hello, world"]
1065         exception_view = DummyView(response)
1066         self._registerView(exception_view, '', IExceptionViewClassifier,
1067                            IRequest, SubException)
1068         environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
1069         start_response = DummyStartResponse()
1070         router = self._makeOne()
1071         self.assertRaises(SuperException, router, environ, start_response)
1072
1073     def test_call_route_raises_sub_exception_super_exception_view(self):
b60bdb 1074         from pyramid.interfaces import IViewClassifier
CM 1075         from pyramid.interfaces import IExceptionViewClassifier
1076         from pyramid.interfaces import IRequest
ff1213 1077         class SuperException(Exception):
CM 1078             pass
1079         class SubException(SuperException):
1080             pass
1081         req_iface = self._registerRouteRequest('foo')
74409d 1082         self._connectRoute('foo', 'archives/:action/:article', None)
ff1213 1083         view = DummyView(DummyResponse(), raise_exception=SubException)
CM 1084         self._registerView(view, '', IViewClassifier, req_iface, None)
1085         response = DummyResponse()
1086         response.app_iter = ["Hello, world"]
1087         exception_view = DummyView(response)
1088         self._registerView(exception_view, '', IExceptionViewClassifier,
1089                            IRequest, SuperException)
1090         environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
1091         start_response = DummyStartResponse()
1092         router = self._makeOne()
1093         result = router(environ, start_response)
1094         self.assertEqual(result, ["Hello, world"])
1095
1096     def test_call_route_raises_exception_another_exception_view(self):
b60bdb 1097         from pyramid.interfaces import IViewClassifier
CM 1098         from pyramid.interfaces import IExceptionViewClassifier
1099         from pyramid.interfaces import IRequest
ff1213 1100         class MyException(Exception):
CM 1101             pass
1102         class AnotherException(Exception):
1103             pass
1104         req_iface = self._registerRouteRequest('foo')
74409d 1105         self._connectRoute('foo', 'archives/:action/:article', None)
ff1213 1106         view = DummyView(DummyResponse(), raise_exception=MyException)
CM 1107         self._registerView(view, '', IViewClassifier, req_iface, None)
1108         response = DummyResponse()
1109         response.app_iter = ["Hello, world"]
1110         exception_view = DummyView(response)
1111         self._registerView(exception_view, '', IExceptionViewClassifier,
1112                            IRequest, AnotherException)
1113         environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
1114         start_response = DummyStartResponse()
1115         router = self._makeOne()
1116         self.assertRaises(MyException, router, environ, start_response)
1117
1118     def test_call_route_raises_exception_view_specializing(self):
b60bdb 1119         from pyramid.interfaces import IViewClassifier
CM 1120         from pyramid.interfaces import IExceptionViewClassifier
1121         from pyramid.interfaces import IRequest
ff1213 1122         req_iface = self._registerRouteRequest('foo')
74409d 1123         self._connectRoute('foo', 'archives/:action/:article', None)
ff1213 1124         view = DummyView(DummyResponse(), raise_exception=RuntimeError)
CM 1125         self._registerView(view, '', IViewClassifier, req_iface, None)
1126         response = DummyResponse()
1127         response.app_iter = ["Hello, world"]
1128         exception_view = DummyView(response)
1129         self._registerView(exception_view, '', IExceptionViewClassifier,
1130                            IRequest, RuntimeError)
1131         response_spec = DummyResponse()
1132         response_spec.app_iter = ["Hello, special world"]
1133         exception_view_spec = DummyView(response_spec)
1134         self._registerView(exception_view_spec, '', IExceptionViewClassifier,
1135                            req_iface, RuntimeError)
1136         environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
1137         start_response = DummyStartResponse()
1138         router = self._makeOne()
1139         result = router(environ, start_response)
1140         self.assertEqual(result, ["Hello, special world"])
1141
1142     def test_call_route_raises_exception_view_another_route(self):
b60bdb 1143         from pyramid.interfaces import IViewClassifier
CM 1144         from pyramid.interfaces import IExceptionViewClassifier
ff1213 1145         req_iface = self._registerRouteRequest('foo')
CM 1146         another_req_iface = self._registerRouteRequest('bar')
74409d 1147         self._connectRoute('foo', 'archives/:action/:article', None)
ff1213 1148         view = DummyView(DummyResponse(), raise_exception=RuntimeError)
CM 1149         self._registerView(view, '', IViewClassifier, req_iface, None)
1150         response = DummyResponse()
1151         response.app_iter = ["Hello, world"]
1152         exception_view = DummyView(response)
1153         self._registerView(exception_view, '', IExceptionViewClassifier,
1154                            another_req_iface, RuntimeError)
1155         environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
1156         start_response = DummyStartResponse()
1157         router = self._makeOne()
1158         self.assertRaises(RuntimeError, router, environ, start_response)
1159
1160     def test_call_view_raises_exception_view_route(self):
b60bdb 1161         from pyramid.interfaces import IRequest
CM 1162         from pyramid.interfaces import IViewClassifier
1163         from pyramid.interfaces import IExceptionViewClassifier
ff1213 1164         req_iface = self._registerRouteRequest('foo')
CM 1165         response = DummyResponse()
1166         exception_response = DummyResponse()
1167         exception_response.app_iter = ["Hello, world"]
1168         view = DummyView(response, raise_exception=RuntimeError)
1169         exception_view = DummyView(exception_response)
1170         environ = self._makeEnviron()
1171         self._registerView(view, '', IViewClassifier, IRequest, None)
1172         self._registerView(exception_view, '', IExceptionViewClassifier,
1173                            req_iface, RuntimeError)
1174         router = self._makeOne()
1175         start_response = DummyStartResponse()
1176         self.assertRaises(RuntimeError, router, environ, start_response)
29f5c1 1177
b3643d 1178     def test_call_view_raises_predicate_mismatch(self):
AL 1179         from pyramid.exceptions import PredicateMismatch
1180         from pyramid.interfaces import IViewClassifier
1181         from pyramid.interfaces import IRequest
1182         view = DummyView(DummyResponse(), raise_exception=PredicateMismatch)
1183         self._registerView(view, '', IViewClassifier, IRequest, None)
1184         environ = self._makeEnviron()
1185         router = self._makeOne()
1186         start_response = DummyStartResponse()
1187         self.assertRaises(PredicateMismatch, router, environ, start_response)
1188
1189     def test_call_view_predicate_mismatch_doesnt_hide_views(self):
1190         from pyramid.exceptions import PredicateMismatch
1191         from pyramid.interfaces import IViewClassifier
1192         from pyramid.interfaces import IRequest, IResponse
1193         from pyramid.response import Response
f3bffd 1194         class BaseContext:
b3643d 1195             pass
f3bffd 1196         class DummyContext(BaseContext):
b3643d 1197             pass
AL 1198         context = DummyContext()
1199         self._registerTraverserFactory(context)
1200         view = DummyView(DummyResponse(), raise_exception=PredicateMismatch)
1201         self._registerView(view, '', IViewClassifier, IRequest,
1202                            DummyContext)
1203         good_view = DummyView('abc')
1204         self._registerView(self.config.derive_view(good_view),
f3bffd 1205                             '', IViewClassifier, IRequest, BaseContext)
b3643d 1206         router = self._makeOne()
AL 1207         def make_response(s):
1208             return Response(s)
1209         router.registry.registerAdapter(make_response, (str,), IResponse)
1210         environ = self._makeEnviron()
1211         start_response = DummyStartResponse()
1212         app_iter = router(environ, start_response)
1213         self.assertEqual(app_iter, [b'abc'])
1214
1215     def test_call_view_multiple_predicate_mismatches_dont_hide_views(self):
1216         from pyramid.exceptions import PredicateMismatch
1217         from pyramid.interfaces import IViewClassifier
1218         from pyramid.interfaces import IRequest, IResponse
1219         from pyramid.response import Response
1220         from zope.interface import Interface, implementer
1221         class IBaseContext(Interface):
1222             pass
1223         class IContext(IBaseContext):
1224             pass
1225         @implementer(IContext)
1226         class DummyContext:
1227             pass
1228         context = DummyContext()
1229         self._registerTraverserFactory(context)
1230         view1 = DummyView(DummyResponse(), raise_exception=PredicateMismatch)
1231         self._registerView(view1, '', IViewClassifier, IRequest,
1232                            DummyContext)
1233         view2 = DummyView(DummyResponse(), raise_exception=PredicateMismatch)
1234         self._registerView(view2, '', IViewClassifier, IRequest,
1235                            IContext)
1236         good_view = DummyView('abc')
1237         self._registerView(self.config.derive_view(good_view),
1238                             '', IViewClassifier, IRequest, IBaseContext)
1239         router = self._makeOne()
1240         def make_response(s):
1241             return Response(s)
1242         router.registry.registerAdapter(make_response, (str,), IResponse)
1243         environ = self._makeEnviron()
1244         start_response = DummyStartResponse()
1245         app_iter = router(environ, start_response)
1246         self.assertEqual(app_iter, [b'abc'])
1247
69c3ad 1248     def test_call_view_predicate_mismatch_doesnt_find_unrelated_views(self):
MM 1249         from pyramid.exceptions import PredicateMismatch
1250         from pyramid.interfaces import IViewClassifier
1251         from pyramid.interfaces import IRequest
1252         from zope.interface import Interface, implementer
1253         class IContext(Interface):
1254             pass
1255         class IOtherContext(Interface):
1256             pass
1257         @implementer(IContext)
1258         class DummyContext:
1259             pass
1260         context = DummyContext()
1261         self._registerTraverserFactory(context)
1262         view = DummyView(DummyResponse(), raise_exception=PredicateMismatch)
1263         self._registerView(view, '', IViewClassifier, IRequest,
1264                            DummyContext)
1265         please_dont_call_me_view = DummyView('abc')
1266         self._registerView(self.config.derive_view(please_dont_call_me_view),
1267                             '', IViewClassifier, IRequest, IOtherContext)
1268         router = self._makeOne()
1269         environ = self._makeEnviron()
1270         router = self._makeOne()
1271         start_response = DummyStartResponse()
1272         self.assertRaises(PredicateMismatch, router, environ, start_response)
1273
0bee84 1274     def test_custom_execution_policy(self):
MM 1275         from pyramid.interfaces import IExecutionPolicy
1276         from pyramid.request import Request
1277         from pyramid.response import Response
1278         registry = self.config.registry
1279         def dummy_policy(environ, router):
1280             return Response(status=200, body=b'foo')
1281         registry.registerUtility(dummy_policy, IExecutionPolicy)
1282         router = self._makeOne()
1283         resp = Request.blank('/').get_response(router)
1284         self.assertEqual(resp.status_code, 200)
1285         self.assertEqual(resp.body, b'foo')
1286
07e0e1 1287     def test_execution_policy_handles_exception(self):
MM 1288         from pyramid.interfaces import IViewClassifier
1289         from pyramid.interfaces import IExceptionViewClassifier
1290         from pyramid.interfaces import IRequest
1291         class Exception1(Exception):
1292             pass
1293         class Exception2(Exception):
1294             pass
1295         req_iface = self._registerRouteRequest('foo')
1296         self._connectRoute('foo', 'archives/:action/:article', None)
1297         view = DummyView(DummyResponse(), raise_exception=Exception1)
1298         self._registerView(view, '', IViewClassifier, req_iface, None)
1299         exception_view1 = DummyView(DummyResponse(),
1300                                     raise_exception=Exception2)
1301         self._registerView(exception_view1, '', IExceptionViewClassifier,
1302                            IRequest, Exception1)
1303         response = DummyResponse()
1304         response.app_iter = ["Hello, world"]
1305         exception_view2 = DummyView(response)
1306         self._registerView(exception_view2, '', IExceptionViewClassifier,
1307                            IRequest, Exception2)
1308         environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
1309         start_response = DummyStartResponse()
1310         router = self._makeOne()
1311         result = router(environ, start_response)
1312         self.assertEqual(result, ["Hello, world"])
1313
0ccdc2 1314 class DummyPredicate(object):
CM 1315     def __call__(self, info, request):
1316         return True
1317     def text(self):
1318         return 'predicate'
1319
5ed24b 1320 class DummyContext:
CM 1321     pass
1322
1eb861 1323 class DummyView:
ff1213 1324     def __init__(self, response, raise_exception=None):
1eb861 1325         self.response = response
ff1213 1326         self.raise_exception = raise_exception
2466f6 1327
1eb861 1328     def __call__(self, context, request):
164677 1329         self.context = context
CM 1330         self.request = request
0f2a11 1331         if self.raise_exception is not None:
ff1213 1332             raise self.raise_exception
1eb861 1333         return self.response
CM 1334
1335 class DummyRootFactory:
1336     def __init__(self, root):
1337         self.root = root
1338
1339     def __call__(self, environ):
1340         return self.root
111593 1341
7de404 1342 class DummyStartResponse:
CM 1343     status = ()
1344     headers = ()
1345     def __call__(self, status, headers):
1346         self.status = status
1347         self.headers = headers
99edc5 1348
d868ff 1349 from pyramid.interfaces import IResponse
3b7334 1350 from zope.interface import implementer
d868ff 1351
3b7334 1352 @implementer(IResponse)
d868ff 1353 class DummyResponse(object):
7de404 1354     headerlist = ()
CM 1355     app_iter = ()
d868ff 1356     environ = None
ef5149 1357     def __init__(self, status='200 OK'):
CM 1358         self.status = status
99edc5 1359
CM 1360     def __call__(self, environ, start_response):
1361         self.environ = environ
1362         start_response(self.status, self.headerlist)
1363         return self.app_iter
7de404 1364     
a1a9fb 1365 class DummyThreadLocalManager:
CM 1366     def __init__(self):
1367         self.pushed = []
1368         self.popped = []
1369
1370     def push(self, val):
1371         self.pushed.append(val)
1372
1373     def pop(self):
1374         self.popped.append(True)
1375     
1376 class DummyAuthenticationPolicy:
1377     pass
c7b7ad 1378
CM 1379 class DummyLogger:
1380     def __init__(self):
1381         self.messages = []
1382     def info(self, msg):
1383         self.messages.append(msg)
1384     warn = info
1385     debug = info
1386
ff1213 1387 def exc_raised(exc, func, *arg, **kw):
CM 1388     try:
1389         func(*arg, **kw)
e91639 1390     except exc as e:
ff1213 1391         return e
CM 1392     else:
1393         raise AssertionError('%s not raised' % exc) # pragma: no cover
1394
1395