[Zope3-checkins] CVS: Zope3/src/zope/app/publication/tests - test_zopepublication.py:1.6

Steve Alexander steve@cat-box.net
Wed, 5 Feb 2003 06:41:33 -0500


Update of /cvs-repository/Zope3/src/zope/app/publication/tests
In directory cvs.zope.org:/tmp/cvs-serv15955/src/zope/app/publication/tests

Modified Files:
	test_zopepublication.py 
Log Message:
You can now define views on exceptions, so that when an error reaches
the publisher, if there's a view on the exception with the default view
name, that view is presented.
If the exception is adaptable to IExceptionSideEffects, then the adapter
is called in a new transaction so that persistent side-effects can be
effected.


=== Zope3/src/zope/app/publication/tests/test_zopepublication.py 1.5 => 1.6 ===
--- Zope3/src/zope/app/publication/tests/test_zopepublication.py:1.5	Mon Dec 30 22:35:09 2002
+++ Zope3/src/zope/app/publication/tests/test_zopepublication.py	Wed Feb  5 06:41:31 2003
@@ -12,6 +12,7 @@
 #
 ##############################################################################
 import unittest
+import sys
 
 from zope.interface.verify import verifyClass
 from zope.interface.implements import instancesOfObjectImplements
@@ -20,6 +21,7 @@
 
 from zope.app.tests.placelesssetup import PlacelessSetup
 from zope.component.adapter import provideAdapter
+from zope.component.view import provideView, setDefaultViewName
 
 from zope.i18n.interfaces import IUserPreferredCharsets
 
@@ -43,9 +45,9 @@
 from zope.component.service import serviceManager
 
 from transaction import get_transaction
+from cStringIO import StringIO
 
 class BasePublicationTests(PlacelessSetup, unittest.TestCase):
-    klass = ZopePublication
 
     def setUp(self):
         PlacelessSetup.setUp(self)
@@ -80,7 +82,7 @@
         PlacelessSetup.tearDown(self)
 
     def testInterfacesVerify(self):
-        for interface in instancesOfObjectImplements(self.klass):
+        for interface in instancesOfObjectImplements(ZopePublication):
             verifyClass(interface, TestPublication)
 
 class Principal:
@@ -131,8 +133,105 @@
         return serviceManager.getService(name)
 
 
+class ZopePublicationErrorHandling(BasePublicationTests):
+
+    def setUp(self):
+        BasePublicationTests.setUp(self)
+        root = self.db.open().root()
+        self.out = StringIO()
+        self.request = TestRequest('/f1/f2', outstream=self.out)
+        from zope.interface import Interface
+        self.presentation_type = Interface
+        self.request._presentation_type = self.presentation_type
+        self.publication = ZopePublication(self.db)
+        self.object = object()  # doesn't matter what it is
+
+    def testRetryAllowed(self):
+        from zodb.interfaces import ConflictError
+        from zope.publisher.interfaces import Retry
+        try:
+            raise ConflictError
+        except:
+            pass
+        self.assertRaises(Retry, self.publication.handleException,
+            self.object, self.request, sys.exc_info(), retry_allowed=True)
+
+    def testRetryNotAllowed(self):
+        from zodb.interfaces import ConflictError
+        from zope.publisher.interfaces import Retry
+        try:
+            raise ConflictError
+        except:
+            pass
+        self.publication.handleException(
+            self.object, self.request, sys.exc_info(), retry_allowed=False)
+        self.request.response.outputBody()
+        value = self.out.getvalue().split()
+        self.assertEqual(' '.join(value[:6]),
+                         'Traceback (most recent call last): File')
+        self.assertEqual(' '.join(value[9:]),
+                         'in testRetryNotAllowed raise ConflictError'
+                         ' ConflictError: database conflict error')
+
+    def testViewOnException(self):
+        from zodb.interfaces import ConflictError
+        from zope.interface import Interface
+        from zope.interface.implements import implements
+        class IConflictError(Interface):
+            pass
+        implements(ConflictError, IConflictError)
+        setDefaultViewName(IConflictError, self.presentation_type, 'name')
+        view_text = 'You had a conflict error'
+        provideView(IConflictError, 'name', self.presentation_type,
+                    [lambda obj,request: lambda: view_text])
+        try:
+            raise ConflictError
+        except:
+            pass
+        self.publication.handleException(
+            self.object, self.request, sys.exc_info(), retry_allowed=False)
+        self.request.response.outputBody()
+        self.assertEqual(self.out.getvalue(), view_text)
+
+    def testExceptionSideEffects(self):
+        from zope.publisher.interfaces import IExceptionSideEffects
+        class SideEffects:
+            __implements__ = IExceptionSideEffects
+            def __init__(self, exception):
+                self.exception = exception
+            def __call__(self, obj, request, exc_info):
+                self.obj = obj
+                self.request = request
+                self.exception_type = exc_info[0]
+                self.exception_from_info = exc_info[1]
+        class SideEffectsFactory:
+            def __call__(self, exception):
+                self.adapter = SideEffects(exception)
+                return self.adapter
+        factory = SideEffectsFactory()
+        from zodb.interfaces import ConflictError
+        from zope.interface import Interface
+        from zope.interface.implements import implements
+        class IConflictError(Interface):
+            pass
+        implements(ConflictError, IConflictError)
+        provideAdapter(IConflictError, IExceptionSideEffects, factory)
+        exception = ConflictError()
+        try:
+            raise exception
+        except:
+            pass
+        self.publication.handleException(
+            self.object, self.request, sys.exc_info(), retry_allowed=False)
+        adapter = factory.adapter
+        self.assertEqual(exception, adapter.exception)
+        self.assertEqual(exception, adapter.exception_from_info)
+        self.assertEqual(ConflictError, adapter.exception_type)
+        self.assertEqual(self.object, adapter.obj)
+        self.assertEqual(self.request, adapter.request)
+
+
 class ZopePublicationTests(BasePublicationTests):
-    klass = ZopePublication
 
     def testPlacefulAuth(self):
         principalRegistry.defineDefaultPrincipal('anonymous', '')
@@ -151,8 +250,7 @@
 
         from zope.component.view import provideView
         from zope.app.interfaces.container import ISimpleReadContainer
-        from zope.app.container.traversal \
-             import ContainerTraverser
+        from zope.app.container.traversal import ContainerTraverser
         from zope.component.interfaces import IPresentation
         provideView(ISimpleReadContainer, '_traverse', IPresentation,
                     ContainerTraverser)
@@ -164,7 +262,7 @@
 
         request.setViewType(IPresentation)
 
-        publication = self.klass(self.db)
+        publication = ZopePublication(self.db)
 
         publication.beforeTraversal(request)
         self.assertEqual(request.user.getId(), 'anonymous')
@@ -179,7 +277,10 @@
         self.assertEqual(request.user.getId(), 'test.bob')
 
 def test_suite():
-    return unittest.makeSuite(ZopePublicationTests)
+    return unittest.TestSuite((
+        unittest.makeSuite(ZopePublicationTests),
+        unittest.makeSuite(ZopePublicationErrorHandling),
+        ))
 
 if __name__ == '__main__':
     unittest.TextTestRunner().run( test_suite() )