1import unittest
2
3from pyramid import testing
4
5class TestRouter(unittest.TestCase):
6    def setUp(self):
7        self.config = testing.setUp()
8        self.registry = self.config.registry
9
10    def tearDown(self):
11        testing.tearDown()
12
13    def _registerRouteRequest(self, name):
14        from pyramid.interfaces import IRouteRequest
15        from pyramid.request import route_request_iface
16        iface = route_request_iface(name)
17        self.registry.registerUtility(iface, IRouteRequest, name=name)
18        return iface
19
20    def _connectRoute(self, name, path, factory=None):
21        from pyramid.interfaces import IRoutesMapper
22        from pyramid.urldispatch import RoutesMapper
23        mapper = self.registry.queryUtility(IRoutesMapper)
24        if mapper is None:
25            mapper = RoutesMapper()
26            self.registry.registerUtility(mapper, IRoutesMapper)
27        return mapper.connect(name, path, factory)
28
29    def _registerLogger(self):
30        from pyramid.interfaces import IDebugLogger
31        logger = DummyLogger()
32        self.registry.registerUtility(logger, IDebugLogger)
33        return logger
34
35    def _registerSettings(self, **kw):
36        settings = {'debug_authorization':False,
37                    'debug_notfound':False,
38                    'debug_routematch':False}
39        settings.update(kw)
40        self.registry.settings = settings
41
42    def _registerTraverserFactory(self, context, view_name='', subpath=None,
43                                  traversed=None, virtual_root=None,
44                                  virtual_root_path=None, raise_error=None,
45                                  **kw):
46        from pyramid.interfaces import ITraverser
47
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:
58            def __init__(self, root):
59                self.root = root
60
61            def __call__(self, request):
62                if raise_error:
63                    raise raise_error
64                values = {'root':self.root,
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
73
74        self.registry.registerAdapter(DummyTraverserFactory, (None,),
75                                      ITraverser, name='')
76
77    def _registerView(self, app, name, classifier, req_iface, ctx_iface):
78        from pyramid.interfaces import IView
79        self.registry.registerAdapter(
80            app, (classifier, req_iface, ctx_iface), IView, name)
81
82    def _registerEventListener(self, iface):
83        L = []
84        def listener(event):
85            L.append(event)
86        self.registry.registerHandler(listener, (iface,))
87        return L
88
89    def _registerRootFactory(self, val):
90        rootfactory = DummyRootFactory(val)
91        from pyramid.interfaces import IRootFactory
92        self.registry.registerUtility(rootfactory, IRootFactory)
93        return rootfactory
94
95    def _getTargetClass(self):
96        from pyramid.router import Router
97        return Router
98
99    def _makeOne(self):
100        klass = self._getTargetClass()
101        return klass(self.registry)
102
103    def _makeEnviron(self, **extras):
104        environ = {
105            'wsgi.url_scheme':'http',
106            'SERVER_NAME':'localhost',
107            'SERVER_PORT':'8080',
108            'REQUEST_METHOD':'GET',
109            'PATH_INFO':'/',
110            }
111        environ.update(extras)
112        return environ
113
114    def test_ctor_registry_has_no_settings(self):
115        self.registry.settings = None
116        router = self._makeOne()
117        self.assertEqual(router.debug_notfound, False)
118        self.assertEqual(router.debug_routematch, False)
119        self.assertFalse('debug_notfound' in router.__dict__)
120        self.assertFalse('debug_routematch' in router.__dict__)
121
122    def test_root_policy(self):
123        context = DummyContext()
124        self._registerTraverserFactory(context)
125        rootfactory = self._registerRootFactory('abc')
126        router = self._makeOne()
127        self.assertEqual(router.root_policy, rootfactory)
128
129    def test_request_factory(self):
130        from pyramid.interfaces import IRequestFactory
131        class DummyRequestFactory(object):
132            pass
133        self.registry.registerUtility(DummyRequestFactory, IRequestFactory)
134        router = self._makeOne()
135        self.assertEqual(router.request_factory, DummyRequestFactory)
136
137    def test_tween_factories(self):
138        from pyramid.interfaces import ITweens
139        from pyramid.config.tweens import Tweens
140        from pyramid.response import Response
141        from pyramid.interfaces import IViewClassifier
142        from pyramid.interfaces import IResponse
143        tweens = Tweens()
144        self.registry.registerUtility(tweens, ITweens)
145        L = []
146        def tween_factory1(handler, registry):
147            L.append((handler, registry))
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
154        def tween_factory2(handler, registry):
155            L.append((handler, registry))
156            def wrapper(request):
157                request.environ['handled'] = ['two']
158                return handler(request)
159            wrapper.name = 'two'
160            wrapper.child = handler
161            return wrapper
162        tweens.add_implicit('one', tween_factory1)
163        tweens.add_implicit('two', tween_factory2)
164        router = self._makeOne()
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)
180        self.assertEqual(app_iter, [b'abc'])
181        self.assertEqual(start_response.status, '200 OK')
182        self.assertEqual(environ['handled'], ['two', 'one'])
183
184    def test_call_traverser_default(self):
185        from pyramid.httpexceptions import HTTPNotFound
186        environ = self._makeEnviron()
187        logger = self._registerLogger()
188        router = self._makeOne()
189        start_response = DummyStartResponse()
190        why = exc_raised(HTTPNotFound, router, environ, start_response)
191        self.assertTrue('/' in why.args[0], why)
192        self.assertFalse('debug_notfound' in why.args[0])
193        self.assertEqual(len(logger.messages), 0)
194
195    def test_traverser_raises_notfound_class(self):
196        from pyramid.httpexceptions import HTTPNotFound
197        environ = self._makeEnviron()
198        context = DummyContext()
199        self._registerTraverserFactory(context, raise_error=HTTPNotFound)
200        router = self._makeOne()
201        start_response = DummyStartResponse()
202        self.assertRaises(HTTPNotFound, router, environ, start_response)
203
204    def test_traverser_raises_notfound_instance(self):
205        from pyramid.httpexceptions import HTTPNotFound
206        environ = self._makeEnviron()
207        context = DummyContext()
208        self._registerTraverserFactory(context, raise_error=HTTPNotFound('foo'))
209        router = self._makeOne()
210        start_response = DummyStartResponse()
211        why = exc_raised(HTTPNotFound, router, environ, start_response)
212        self.assertTrue('foo' in why.args[0], why)
213
214    def test_traverser_raises_forbidden_class(self):
215        from pyramid.httpexceptions import HTTPForbidden
216        environ = self._makeEnviron()
217        context = DummyContext()
218        self._registerTraverserFactory(context, raise_error=HTTPForbidden)
219        router = self._makeOne()
220        start_response = DummyStartResponse()
221        self.assertRaises(HTTPForbidden, router, environ, start_response)
222
223    def test_traverser_raises_forbidden_instance(self):
224        from pyramid.httpexceptions import HTTPForbidden
225        environ = self._makeEnviron()
226        context = DummyContext()
227        self._registerTraverserFactory(context,
228                                       raise_error=HTTPForbidden('foo'))
229        router = self._makeOne()
230        start_response = DummyStartResponse()
231        why = exc_raised(HTTPForbidden, router, environ, start_response)
232        self.assertTrue('foo' in why.args[0], why)
233
234    def test_call_no_view_registered_no_isettings(self):
235        from pyramid.httpexceptions import HTTPNotFound
236        environ = self._makeEnviron()
237        context = DummyContext()
238        self._registerTraverserFactory(context)
239        logger = self._registerLogger()
240        router = self._makeOne()
241        start_response = DummyStartResponse()
242        why = exc_raised(HTTPNotFound, router, environ, start_response)
243        self.assertTrue('/' in why.args[0], why)
244        self.assertFalse('debug_notfound' in why.args[0])
245        self.assertEqual(len(logger.messages), 0)
246
247    def test_call_no_view_registered_debug_notfound_false(self):
248        from pyramid.httpexceptions import HTTPNotFound
249        environ = self._makeEnviron()
250        context = DummyContext()
251        self._registerTraverserFactory(context)
252        logger = self._registerLogger()
253        self._registerSettings(debug_notfound=False)
254        router = self._makeOne()
255        start_response = DummyStartResponse()
256        why = exc_raised(HTTPNotFound, router, environ, start_response)
257        self.assertTrue('/' in why.args[0], why)
258        self.assertFalse('debug_notfound' in why.args[0])
259        self.assertEqual(len(logger.messages), 0)
260
261    def test_call_no_view_registered_debug_notfound_true(self):
262        from pyramid.httpexceptions import HTTPNotFound
263        environ = self._makeEnviron()
264        context = DummyContext()
265        self._registerTraverserFactory(context)
266        self._registerSettings(debug_notfound=True)
267        logger = self._registerLogger()
268        router = self._makeOne()
269        start_response = DummyStartResponse()
270        why = exc_raised(HTTPNotFound, router, environ, start_response)
271        self.assertTrue(
272            "debug_notfound of url http://localhost:8080/; " in why.args[0])
273        self.assertTrue("view_name: '', subpath: []" in why.args[0])
274        self.assertTrue('http://localhost:8080' in why.args[0], why)
275
276        self.assertEqual(len(logger.messages), 1)
277        message = logger.messages[0]
278        self.assertTrue('of url http://localhost:8080' in message)
279        self.assertTrue("path_info: " in message)
280        self.assertTrue('DummyContext' in message)
281        self.assertTrue("view_name: ''" in message)
282        self.assertTrue("subpath: []" in message)
283
284    def test_call_view_returns_non_iresponse(self):
285        from pyramid.interfaces import IViewClassifier
286        context = DummyContext()
287        self._registerTraverserFactory(context)
288        environ = self._makeEnviron()
289        view = DummyView('abc')
290        self._registerView(self.config.derive_view(view), '', IViewClassifier,
291                           None, None)
292        router = self._makeOne()
293        start_response = DummyStartResponse()
294        self.assertRaises(ValueError, router, environ, start_response)
295
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')
304        self._registerView(self.config.derive_view(view), '',
305                           IViewClassifier, None, None)
306        router = self._makeOne()
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)
312        self.assertEqual(app_iter, [b'abc'])
313        self.assertEqual(start_response.status, '200 OK')
314
315    def test_call_with_request_extensions(self):
316        from pyramid.interfaces import IViewClassifier
317        from pyramid.interfaces import IRequestExtensions
318        from pyramid.interfaces import IRequest
319        from pyramid.request import Request
320        from pyramid.util import InstancePropertyHelper
321        context = DummyContext()
322        self._registerTraverserFactory(context)
323        class Extensions(object):
324            def __init__(self):
325                self.methods = {}
326                self.descriptors = {}
327        extensions = Extensions()
328        ext_method = lambda r: 'bar'
329        name, fn = InstancePropertyHelper.make_property(ext_method, name='foo')
330        extensions.descriptors[name] = fn
331        request = Request.blank('/')
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)
347        self.assertEqual(view.request.foo, 'bar')
348
349    def test_call_view_registered_nonspecific_default_path(self):
350        from pyramid.interfaces import IViewClassifier
351        context = DummyContext()
352        self._registerTraverserFactory(context)
353        response = DummyResponse()
354        response.app_iter = ['Hello world']
355        view = DummyView(response)
356        environ = self._makeEnviron()
357        self._registerView(self.config.derive_view(view), '',
358                           IViewClassifier, None, None)
359        self._registerRootFactory(context)
360        router = self._makeOne()
361        start_response = DummyStartResponse()
362        result = router(environ, start_response)
363        self.assertEqual(result, ['Hello world'])
364        self.assertEqual(start_response.headers, ())
365        self.assertEqual(start_response.status, '200 OK')
366        request = view.request
367        self.assertEqual(request.view_name, '')
368        self.assertEqual(request.subpath, [])
369        self.assertEqual(request.context, context)
370        self.assertEqual(request.root, context)
371
372    def test_call_view_registered_nonspecific_nondefault_path_and_subpath(self):
373        from pyramid.interfaces import IViewClassifier
374        context = DummyContext()
375        self._registerTraverserFactory(context, view_name='foo',
376                                       subpath=['bar'],
377                                       traversed=['context'])
378        self._registerRootFactory(context)
379        response = DummyResponse()
380        response.app_iter = ['Hello world']
381        view = DummyView(response)
382        environ = self._makeEnviron()
383        self._registerView(view, 'foo', IViewClassifier, None, None)
384        router = self._makeOne()
385        start_response = DummyStartResponse()
386        result = router(environ, start_response)
387        self.assertEqual(result, ['Hello world'])
388        self.assertEqual(start_response.headers, ())
389        self.assertEqual(start_response.status, '200 OK')
390        request = view.request
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)
395
396    def test_call_view_registered_specific_success(self):
397        from zope.interface import Interface
398        from zope.interface import directlyProvides
399        class IContext(Interface):
400            pass
401        from pyramid.interfaces import IRequest
402        from pyramid.interfaces import IViewClassifier
403        context = DummyContext()
404        directlyProvides(context, IContext)
405        self._registerTraverserFactory(context)
406        self._registerRootFactory(context)
407        response = DummyResponse()
408        response.app_iter = ['Hello world']
409        view = DummyView(response)
410        environ = self._makeEnviron()
411        self._registerView(view, '', IViewClassifier, IRequest, IContext)
412        router = self._makeOne()
413        start_response = DummyStartResponse()
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')
418        request = view.request
419        self.assertEqual(request.view_name, '')
420        self.assertEqual(request.subpath, [])
421        self.assertEqual(request.context, context)
422        self.assertEqual(request.root, context)
423
424    def test_call_view_registered_specific_fail(self):
425        from zope.interface import Interface
426        from zope.interface import directlyProvides
427        from pyramid.httpexceptions import HTTPNotFound
428        from pyramid.interfaces import IViewClassifier
429        class IContext(Interface):
430            pass
431        class INotContext(Interface):
432            pass
433        from pyramid.interfaces import IRequest
434        context = DummyContext()
435        directlyProvides(context, INotContext)
436        self._registerTraverserFactory(context, subpath=[''])
437        response = DummyResponse()
438        view = DummyView(response)
439        environ = self._makeEnviron()
440        self._registerView(view, '', IViewClassifier, IRequest, IContext)
441        router = self._makeOne()
442        start_response = DummyStartResponse()
443        self.assertRaises(HTTPNotFound, router, environ, start_response)
444
445    def test_call_view_raises_forbidden(self):
446        from zope.interface import Interface
447        from zope.interface import directlyProvides
448        from pyramid.httpexceptions import HTTPForbidden
449        class IContext(Interface):
450            pass
451        from pyramid.interfaces import IRequest
452        from pyramid.interfaces import IViewClassifier
453        context = DummyContext()
454        directlyProvides(context, IContext)
455        self._registerTraverserFactory(context, subpath=[''])
456        response = DummyResponse()
457        view = DummyView(response,
458                         raise_exception=HTTPForbidden("unauthorized"))
459        environ = self._makeEnviron()
460        self._registerView(view, '', IViewClassifier, IRequest, IContext)
461        router = self._makeOne()
462        start_response = DummyStartResponse()
463        why = exc_raised(HTTPForbidden, router, environ, start_response)
464        self.assertEqual(why.args[0], 'unauthorized')
465
466    def test_call_view_raises_notfound(self):
467        from zope.interface import Interface
468        from zope.interface import directlyProvides
469        class IContext(Interface):
470            pass
471        from pyramid.interfaces import IRequest
472        from pyramid.interfaces import IViewClassifier
473        from pyramid.httpexceptions import HTTPNotFound
474        context = DummyContext()
475        directlyProvides(context, IContext)
476        self._registerTraverserFactory(context, subpath=[''])
477        response = DummyResponse()
478        view = DummyView(response, raise_exception=HTTPNotFound("notfound"))
479        environ = self._makeEnviron()
480        self._registerView(view, '', IViewClassifier, IRequest, IContext)
481        router = self._makeOne()
482        start_response = DummyStartResponse()
483        why = exc_raised(HTTPNotFound, router, environ, start_response)
484        self.assertEqual(why.args[0], 'notfound')
485
486    def test_call_view_raises_response_cleared(self):
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):
501            self.assertFalse(hasattr(request.response, 'a'))
502            request.response.body = b'OK'
503            return request.response
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)
511        self.assertEqual(itera, [b'OK'])
512
513    def test_call_request_has_response_callbacks(self):
514        from zope.interface import Interface
515        from zope.interface import directlyProvides
516        class IContext(Interface):
517            pass
518        from pyramid.interfaces import IRequest
519        from pyramid.interfaces import IViewClassifier
520        context = DummyContext()
521        directlyProvides(context, IContext)
522        self._registerTraverserFactory(context, subpath=[''])
523        response = DummyResponse('200 OK')
524        def view(context, request):
525            def callback(request, response):
526                response.called_back = True
527            request.add_response_callback(callback)
528            return response
529        environ = self._makeEnviron()
530        self._registerView(view, '', IViewClassifier, IRequest, IContext)
531        router = self._makeOne()
532        start_response = DummyStartResponse()
533        router(environ, start_response)
534        self.assertEqual(response.called_back, True)
535
536    def test_call_request_has_finished_callbacks_when_view_succeeds(self):
537        from zope.interface import Interface
538        from zope.interface import directlyProvides
539        class IContext(Interface):
540            pass
541        from pyramid.interfaces import IRequest
542        from pyramid.interfaces import IViewClassifier
543        context = DummyContext()
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
550            request.add_finished_callback(callback)
551            return response
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
564        from pyramid.interfaces import IRequest
565        from pyramid.interfaces import IViewClassifier
566        context = DummyContext()
567        directlyProvides(context, IContext)
568        self._registerTraverserFactory(context, subpath=[''])
569        def view(context, request):
570            def callback(request):
571                request.environ['called_back'] = True
572            request.add_finished_callback(callback)
573            raise NotImplementedError
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)
580
581    def test_call_request_factory_raises(self):
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
591    def test_call_eventsends(self):
592        from pyramid.interfaces import INewRequest
593        from pyramid.interfaces import INewResponse
594        from pyramid.interfaces import IBeforeTraversal
595        from pyramid.interfaces import IContextFound
596        from pyramid.interfaces import IViewClassifier
597        context = DummyContext()
598        self._registerTraverserFactory(context)
599        response = DummyResponse()
600        response.app_iter = ['Hello world']
601        view = DummyView(response)
602        environ = self._makeEnviron()
603        self._registerView(view, '', IViewClassifier, None, None)
604        request_events = self._registerEventListener(INewRequest)
605        beforetraversal_events = self._registerEventListener(IBeforeTraversal)
606        context_found_events = self._registerEventListener(IContextFound)
607        response_events = self._registerEventListener(INewResponse)
608        router = self._makeOne()
609        start_response = DummyStartResponse()
610        result = router(environ, start_response)
611        self.assertEqual(len(request_events), 1)
612        self.assertEqual(request_events[0].request.environ, environ)
613        self.assertEqual(len(beforetraversal_events), 1)
614        self.assertEqual(beforetraversal_events[0].request.environ, environ)
615        self.assertEqual(len(context_found_events), 1)
616        self.assertEqual(context_found_events[0].request.environ, environ)
617        self.assertEqual(context_found_events[0].request.context, context)
618        self.assertEqual(len(response_events), 1)
619        self.assertEqual(response_events[0].response, response)
620        self.assertEqual(response_events[0].request.context, context)
621        self.assertEqual(result, response.app_iter)
622
623    def test_call_newrequest_evllist_exc_can_be_caught_by_exceptionview(self):
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
644    def test_call_pushes_and_pops_threadlocal_manager(self):
645        from pyramid.interfaces import IViewClassifier
646        context = DummyContext()
647        self._registerTraverserFactory(context)
648        response = DummyResponse()
649        response.app_iter = ['Hello world']
650        view = DummyView(response)
651        environ = self._makeEnviron()
652        self._registerView(view, '', IViewClassifier, None, None)
653        router = self._makeOne()
654        start_response = DummyStartResponse()
655        router.threadlocal_manager = DummyThreadLocalManager()
656        router(environ, start_response)
657        self.assertEqual(len(router.threadlocal_manager.pushed), 1)
658        self.assertEqual(len(router.threadlocal_manager.popped), 1)
659
660    def test_call_route_matches_and_has_factory(self):
661        from pyramid.interfaces import IViewClassifier
662        logger = self._registerLogger()
663        self._registerSettings(debug_routematch=True)
664        self._registerRouteRequest('foo')
665        root = object()
666        def factory(request):
667            return root
668        route = self._connectRoute('foo', 'archives/:action/:article', factory)
669        route.predicates = [DummyPredicate()]
670        context = DummyContext()
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')
676        self._registerView(view, '', IViewClassifier, None, None)
677        self._registerRootFactory(context)
678        router = self._makeOne()
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)
689        matchdict = {'action':'action1', 'article':'article1'}
690        self.assertEqual(request.matchdict, matchdict)
691        self.assertEqual(request.matched_route.name, 'foo')
692        self.assertEqual(len(logger.messages), 1)
693        self.assertTrue(
694            logger.messages[0].startswith(
695            "route matched for url http://localhost:8080"
696            "/archives/action1/article1; "
697            "route_name: 'foo', "
698            "path_info: ")
699            )
700        self.assertTrue(
701            "predicates: 'predicate'" in logger.messages[0]
702            )
703
704    def test_call_route_match_miss_debug_routematch(self):
705        from pyramid.httpexceptions import HTTPNotFound
706        logger = self._registerLogger()
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()
716        self.assertRaises(HTTPNotFound, router, environ, start_response)
717
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
723    def test_call_route_matches_doesnt_overwrite_subscriber_iface(self):
724        from pyramid.interfaces import INewRequest
725        from pyramid.interfaces import IViewClassifier
726        from zope.interface import alsoProvides
727        from zope.interface import Interface
728        self._registerRouteRequest('foo')
729        class IFoo(Interface):
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
737        self._connectRoute('foo', 'archives/:action/:article', factory)
738        context = DummyContext()
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')
744        self._registerView(view, '', IViewClassifier, None, None)
745        self._registerRootFactory(context)
746        router = self._makeOne()
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)
757        matchdict = {'action':'action1', 'article':'article1'}
758        self.assertEqual(request.matchdict, matchdict)
759        self.assertEqual(request.matched_route.name, 'foo')
760        self.assertTrue(IFoo.providedBy(request))
761
762    def test_root_factory_raises_notfound(self):
763        from pyramid.interfaces import IRootFactory
764        from pyramid.httpexceptions import HTTPNotFound
765        from zope.interface import Interface
766        from zope.interface import directlyProvides
767        def rootfactory(request):
768            raise HTTPNotFound('from root factory')
769        self.registry.registerUtility(rootfactory, IRootFactory)
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()
777        why = exc_raised(HTTPNotFound, router, environ, start_response)
778        self.assertTrue('from root factory' in why.args[0])
779
780    def test_root_factory_raises_forbidden(self):
781        from pyramid.interfaces import IRootFactory
782        from pyramid.httpexceptions import HTTPForbidden
783        from zope.interface import Interface
784        from zope.interface import directlyProvides
785        def rootfactory(request):
786            raise HTTPForbidden('from root factory')
787        self.registry.registerUtility(rootfactory, IRootFactory)
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()
795        why = exc_raised(HTTPForbidden, router, environ, start_response)
796        self.assertTrue('from root factory' in why.args[0])
797
798    def test_root_factory_exception_propagating(self):
799        from pyramid.interfaces import IRootFactory
800        from zope.interface import Interface
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
827        from pyramid.interfaces import IRequest
828        from pyramid.interfaces import IViewClassifier
829        from pyramid.interfaces import IRequestFactory
830        from pyramid.interfaces import IExceptionViewClassifier
831        def rfactory(environ):
832            return request
833        self.registry.registerUtility(rfactory, IRequestFactory)
834        from pyramid.request import Request
835        request = Request.blank('/')
836        context = DummyContext()
837        directlyProvides(context, IContext)
838        self._registerTraverserFactory(context, subpath=[''])
839        response = DummyResponse()
840        response.app_iter = ['OK']
841        error = RuntimeError()
842        view = DummyView(response, raise_exception=error)
843        environ = self._makeEnviron()
844        def exception_view(context, request):
845            self.assertEqual(request.exc_info[0], RuntimeError)
846            return response
847        self._registerView(view, '', IViewClassifier, IRequest, IContext)
848        self._registerView(exception_view, '', IExceptionViewClassifier,
849                           IRequest, RuntimeError)
850        router = self._makeOne()
851        start_response = DummyStartResponse()
852        result = router(environ, start_response)
853        self.assertEqual(result, ['OK'])
854        # exc_info and exception should still be around on the request after
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,))
859
860    def test_call_view_raises_exception_view(self):
861        from pyramid.interfaces import IViewClassifier
862        from pyramid.interfaces import IExceptionViewClassifier
863        from pyramid.interfaces import IRequest
864        response = DummyResponse()
865        exception_response = DummyResponse()
866        exception_response.app_iter = ["Hello, world"]
867        view = DummyView(response, raise_exception=RuntimeError)
868        def exception_view(context, request):
869            self.assertEqual(request.exception.__class__, RuntimeError)
870            return exception_response
871        environ = self._makeEnviron()
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):
881        from pyramid.interfaces import IViewClassifier
882        from pyramid.interfaces import IExceptionViewClassifier
883        from pyramid.interfaces import IRequest
884        class SuperException(Exception):
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):
902        from pyramid.interfaces import IViewClassifier
903        from pyramid.interfaces import IExceptionViewClassifier
904        from pyramid.interfaces import IRequest
905        class SuperException(Exception):
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):
924        from pyramid.interfaces import IViewClassifier
925        from pyramid.interfaces import IExceptionViewClassifier
926        from pyramid.interfaces import IRequest
927        class MyException(Exception):
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):
945        from pyramid.interfaces import IRootFactory
946        from pyramid.interfaces import IRequest
947        from pyramid.interfaces import IExceptionViewClassifier
948        def rootfactory(request):
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()
959        app_iter = router(environ, start_response)
960        self.assertEqual(app_iter, ["Hello, world"])
961
962    def test_traverser_raises_exception_view(self):
963        from pyramid.interfaces import IRequest
964        from pyramid.interfaces import IExceptionViewClassifier
965        environ = self._makeEnviron()
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
978    def test_exception_view_returns_non_iresponse(self):
979        from pyramid.interfaces import IRequest
980        from pyramid.interfaces import IViewClassifier
981        from pyramid.interfaces import IExceptionViewClassifier
982        environ = self._makeEnviron()
983        response = DummyResponse()
984        view = DummyView(response, raise_exception=RuntimeError)
985
986        self._registerView(self.config.derive_view(view), '',
987                           IViewClassifier, IRequest, None)
988        exception_view = DummyView(None)
989        self._registerView(self.config.derive_view(exception_view), '',
990                           IExceptionViewClassifier,
991                           IRequest, RuntimeError)
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):
997        from pyramid.interfaces import IViewClassifier
998        from pyramid.interfaces import IExceptionViewClassifier
999        req_iface = self._registerRouteRequest('foo')
1000        self._connectRoute('foo', 'archives/:action/:article', None)
1001        view = DummyView(DummyResponse(), raise_exception=RuntimeError)
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):
1015        from pyramid.interfaces import IViewClassifier
1016        from pyramid.interfaces import IExceptionViewClassifier
1017        from pyramid.interfaces import IRequest
1018        req_iface = self._registerRouteRequest('foo')
1019        self._connectRoute('foo', 'archives/:action/:article', None)
1020        view = DummyView(DummyResponse(), raise_exception=RuntimeError)
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):
1033        from pyramid.interfaces import IViewClassifier
1034        from pyramid.interfaces import IExceptionViewClassifier
1035        from pyramid.interfaces import IRequest
1036        req_iface = self._registerRouteRequest('foo')
1037        self._connectRoute('foo', 'archives/:action/:article', None)
1038        view = DummyView(DummyResponse(), raise_exception=RuntimeError)
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):
1052        from pyramid.interfaces import IViewClassifier
1053        from pyramid.interfaces import IExceptionViewClassifier
1054        from pyramid.interfaces import IRequest
1055        class SuperException(Exception):
1056            pass
1057        class SubException(SuperException):
1058            pass
1059        req_iface = self._registerRouteRequest('foo')
1060        self._connectRoute('foo', 'archives/:action/:article', None)
1061        view = DummyView(DummyResponse(), raise_exception=SuperException)
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):
1074        from pyramid.interfaces import IViewClassifier
1075        from pyramid.interfaces import IExceptionViewClassifier
1076        from pyramid.interfaces import IRequest
1077        class SuperException(Exception):
1078            pass
1079        class SubException(SuperException):
1080            pass
1081        req_iface = self._registerRouteRequest('foo')
1082        self._connectRoute('foo', 'archives/:action/:article', None)
1083        view = DummyView(DummyResponse(), raise_exception=SubException)
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):
1097        from pyramid.interfaces import IViewClassifier
1098        from pyramid.interfaces import IExceptionViewClassifier
1099        from pyramid.interfaces import IRequest
1100        class MyException(Exception):
1101            pass
1102        class AnotherException(Exception):
1103            pass
1104        req_iface = self._registerRouteRequest('foo')
1105        self._connectRoute('foo', 'archives/:action/:article', None)
1106        view = DummyView(DummyResponse(), raise_exception=MyException)
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):
1119        from pyramid.interfaces import IViewClassifier
1120        from pyramid.interfaces import IExceptionViewClassifier
1121        from pyramid.interfaces import IRequest
1122        req_iface = self._registerRouteRequest('foo')
1123        self._connectRoute('foo', 'archives/:action/:article', None)
1124        view = DummyView(DummyResponse(), raise_exception=RuntimeError)
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):
1143        from pyramid.interfaces import IViewClassifier
1144        from pyramid.interfaces import IExceptionViewClassifier
1145        req_iface = self._registerRouteRequest('foo')
1146        another_req_iface = self._registerRouteRequest('bar')
1147        self._connectRoute('foo', 'archives/:action/:article', None)
1148        view = DummyView(DummyResponse(), raise_exception=RuntimeError)
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):
1161        from pyramid.interfaces import IRequest
1162        from pyramid.interfaces import IViewClassifier
1163        from pyramid.interfaces import IExceptionViewClassifier
1164        req_iface = self._registerRouteRequest('foo')
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)
1177
1178    def test_call_view_raises_predicate_mismatch(self):
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
1194        class BaseContext:
1195            pass
1196        class DummyContext(BaseContext):
1197            pass
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),
1205                            '', IViewClassifier, IRequest, BaseContext)
1206        router = self._makeOne()
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
1248    def test_call_view_predicate_mismatch_doesnt_find_unrelated_views(self):
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
1274class DummyPredicate(object):
1275    def __call__(self, info, request):
1276        return True
1277    def text(self):
1278        return 'predicate'
1279
1280class DummyContext:
1281    pass
1282
1283class DummyView:
1284    def __init__(self, response, raise_exception=None):
1285        self.response = response
1286        self.raise_exception = raise_exception
1287
1288    def __call__(self, context, request):
1289        self.context = context
1290        self.request = request
1291        if self.raise_exception is not None:
1292            raise self.raise_exception
1293        return self.response
1294
1295class DummyRootFactory:
1296    def __init__(self, root):
1297        self.root = root
1298
1299    def __call__(self, environ):
1300        return self.root
1301
1302class DummyStartResponse:
1303    status = ()
1304    headers = ()
1305    def __call__(self, status, headers):
1306        self.status = status
1307        self.headers = headers
1308
1309from pyramid.interfaces import IResponse
1310from zope.interface import implementer
1311
1312@implementer(IResponse)
1313class DummyResponse(object):
1314    headerlist = ()
1315    app_iter = ()
1316    environ = None
1317    def __init__(self, status='200 OK'):
1318        self.status = status
1319
1320    def __call__(self, environ, start_response):
1321        self.environ = environ
1322        start_response(self.status, self.headerlist)
1323        return self.app_iter
1324
1325class DummyThreadLocalManager:
1326    def __init__(self):
1327        self.pushed = []
1328        self.popped = []
1329
1330    def push(self, val):
1331        self.pushed.append(val)
1332
1333    def pop(self):
1334        self.popped.append(True)
1335
1336class DummyAuthenticationPolicy:
1337    pass
1338
1339class DummyLogger:
1340    def __init__(self):
1341        self.messages = []
1342    def info(self, msg):
1343        self.messages.append(msg)
1344    warn = info
1345    debug = info
1346
1347def exc_raised(exc, func, *arg, **kw):
1348    try:
1349        func(*arg, **kw)
1350    except exc as e:
1351        return e
1352    else:
1353        raise AssertionError('%s not raised' % exc) # pragma: no cover
1354
1355
1356