[Checkins] SVN: zope.webdav/trunk/src/zope/webdav/ Add unit tests for the MKCOL implementation.

Michael Kerrin michael.kerrin at openapp.biz
Sat Feb 3 14:32:19 EST 2007


Log message for revision 72355:
  Add unit tests for the MKCOL implementation.
  
  Add more tests for the 'include' XML element when the
  requesting property is either unauthorized or broken.
  

Changed:
  U   zope.webdav/trunk/src/zope/webdav/configure.zcml
  U   zope.webdav/trunk/src/zope/webdav/mkcol.py
  U   zope.webdav/trunk/src/zope/webdav/tests/test_doctests.py
  U   zope.webdav/trunk/src/zope/webdav/tests/test_propfind.py

-=-
Modified: zope.webdav/trunk/src/zope/webdav/configure.zcml
===================================================================
--- zope.webdav/trunk/src/zope/webdav/configure.zcml	2007-02-03 19:16:54 UTC (rev 72354)
+++ zope.webdav/trunk/src/zope/webdav/configure.zcml	2007-02-03 19:32:19 UTC (rev 72355)
@@ -26,7 +26,7 @@
      />
 
   <adapter
-     factory=".mkcol.NullResource"
+     factory=".mkcol.MKCOL"
      name="MKCOL"
      />
 

Modified: zope.webdav/trunk/src/zope/webdav/mkcol.py
===================================================================
--- zope.webdav/trunk/src/zope/webdav/mkcol.py	2007-02-03 19:16:54 UTC (rev 72354)
+++ zope.webdav/trunk/src/zope/webdav/mkcol.py	2007-02-03 19:32:19 UTC (rev 72355)
@@ -25,10 +25,128 @@
 
 import zope.webdav.interfaces
 
-class NullResource(object):
-    """MKCOL handler for creating collections"""
+class MKCOL(object):
+    """
+    MKCOL handler for creating collections. This is only supported on
+    unmapped urls.
 
-    # MKCOL is only supported on unmapped urls.
+      >>> from cStringIO import StringIO
+      >>> from zope import component
+      >>> from zope.publisher.browser import TestRequest
+      >>> from zope.app.http.put import NullResource
+      >>> from zope.app.folder.folder import Folder
+      >>> from zope.app.folder.interfaces import IFolder
+
+      >>> events = []
+      >>> def eventLog(event):
+      ...    events.append(event)
+      >>> zope.event.subscribers.append(eventLog)
+
+      >>> container = Folder()
+      >>> context = NullResource(container, 'newdir')
+
+    A MKCOL request message may contain a message body. But the specification
+    says that if the server receives a entity type that it doesn't understand
+    then it MOST respond with a 415 (Unsupported Media Type). This
+    implementation of MKCOL doesn't understand any message body received
+    with a MKCOL request and thus raise a UnsupportedMediaType exception.
+
+      >>> mkcol = MKCOL(context, TestRequest(StringIO('some request body')))
+      >>> mkcol.MKCOL() #doctest:+ELLIPSIS
+      Traceback (most recent call last):
+      ...
+      UnsupportedMediaType: <zope.app.http.put.NullResource object at ...>, u'A request body is not supported for a MKCOL method'
+      >>> events
+      []
+
+    If no adapter implementing IWriteDirectory is registered for then we
+    will never be able to create a new collection and hence this operation
+    is forbidden.
+
+      >>> MKCOL(context, TestRequest()).MKCOL()
+      Traceback (most recent call last):
+      ...
+      ForbiddenError
+      >>> 'newdir' in container
+      False
+      >>> events
+      []
+
+    Now we will define and register a IWriteDirectory adapter. But we
+    can't adapt the container to IDirectoryFactory (which creates the
+    new collection object) so again this operation is forbidden.
+
+      >>> class WriteDirectory(object):
+      ...    interface.implements(IWriteDirectory)
+      ...    component.adapts(IFolder)
+      ...    def __init__(self, context):
+      ...        self.context = context
+      ...    def __setitem__(self, name, object):
+      ...        self.context[name] = object
+      ...    def __delitem__(slef, name):
+      ...        del self.context[name]
+      >>> component.getGlobalSiteManager().registerAdapter(WriteDirectory)
+
+      >>> events = []
+
+      >>> MKCOL(context, TestRequest()).MKCOL()
+      Traceback (most recent call last):
+      ...
+      ForbiddenError
+      >>> 'newdir' in container
+      False
+      >>> events
+      []
+
+    By defining and registering a directory factory we can create a new
+    collection.
+
+      >>> class DirectoryFactory(object):
+      ...    interface.implements(IDirectoryFactory)
+      ...    component.adapts(IFolder)
+      ...    def __init__(self, context):
+      ...        pass
+      ...    def __call__(self, name):
+      ...        return Folder()
+      >>> component.getGlobalSiteManager().registerAdapter(DirectoryFactory)
+      >>> events = []
+
+      >>> request = TestRequest()
+
+    The next call to the mkcol implementation will succeed and create
+    a new folder with the name 'newdir'.
+      
+      >>> MKCOL(context, request).MKCOL()
+      ''
+      >>> request.response.getStatus()
+      201
+      >>> 'newdir' in container
+      True
+      >>> container['newdir'] #doctest:+ELLIPSIS
+      <zope.app.folder.folder.Folder object at ...>
+
+    Verify that the correct events are generated during the creation of the
+    new folder.
+
+      >>> events[0] #doctest:+ELLIPSIS
+      <zope.app.event.objectevent.ObjectCreatedEvent object at ...>
+      >>> events[1] #doctest:+ELLIPSIS
+      <zope.app.container.contained.ObjectAddedEvent object at ...>
+      >>> events[2] #doctest:+ELLIPSIS
+      <zope.app.container.contained.ContainerModifiedEvent object at ...>
+      >>> events[3:]
+      []
+
+    Cleanup.
+
+      >>> component.getGlobalSiteManager().unregisterAdapter(WriteDirectory)
+      True
+      >>> component.getGlobalSiteManager().unregisterAdapter(DirectoryFactory)
+      True
+
+      >>> zope.event.subscribers.remove(eventLog)
+
+    """
     interface.implements(zope.webdav.interfaces.IWebDAVMethod)
     component.adapts(zope.app.http.interfaces.INullResource,
                      zope.webdav.interfaces.IWebDAVRequest)
@@ -50,12 +168,12 @@
         name = self.context.name
 
         dir = IWriteDirectory(container, None)
-        if dir is None:
+        dir_factory = IDirectoryFactory(container, None)
+        if dir is None or dir_factory is None:
             raise zope.webdav.interfaces.ForbiddenError(
                 self.context, message = u"")
-
-        factory = IDirectoryFactory(container)
-        newdir = factory(name)
+        
+        newdir = dir_factory(name)
         zope.event.notify(ObjectCreatedEvent(newdir))
         dir[name] = newdir
 

Modified: zope.webdav/trunk/src/zope/webdav/tests/test_doctests.py
===================================================================
--- zope.webdav/trunk/src/zope/webdav/tests/test_doctests.py	2007-02-03 19:16:54 UTC (rev 72354)
+++ zope.webdav/trunk/src/zope/webdav/tests/test_doctests.py	2007-02-03 19:32:19 UTC (rev 72355)
@@ -199,4 +199,5 @@
                              setUp = lockingSetUp, tearDown = lockingTearDown),
         doctest.DocTestSuite("zope.webdav.deadproperties"),
         doctest.DocTestSuite("zope.webdav.adapters"),
+        doctest.DocTestSuite("zope.webdav.mkcol"),
         ))

Modified: zope.webdav/trunk/src/zope/webdav/tests/test_propfind.py
===================================================================
--- zope.webdav/trunk/src/zope/webdav/tests/test_propfind.py	2007-02-03 19:16:54 UTC (rev 72354)
+++ zope.webdav/trunk/src/zope/webdav/tests/test_propfind.py	2007-02-03 19:32:19 UTC (rev 72355)
@@ -597,10 +597,11 @@
                                    status = 500)
 
         # now check that the error reporting utility caught the error.
+        self.assertEqual(len(self.errUtility.errors), 1)
         error = self.errUtility.errors[0]
         self.assertEqual(isinstance(error[0][1], NotImplementedError), True)
 
-    def test_renderUnauthorizedProperty(self):
+    def test_render_selected_unauthorizedProperty(self):
         resource = Resource("some text", 10)
         request = zope.webdav.publisher.WebDAVRequest(StringIO(""), {})
         propf = PROPFIND(None, None)
@@ -626,6 +627,9 @@
         # does throw the exception.
 
     def test_renderAllProperties_unauthorized(self):
+        # If we request to render all property but we are unauthorized to
+        # access one of the propertues then this property should be threated
+        # as if it were restricted property and not returned to the user.
         resource = Resource("some text", 10)
         request = zope.webdav.publisher.WebDAVRequest(StringIO(""), {})
         propf = PROPFIND(None, request)
@@ -652,7 +656,55 @@
                      "The unauthprop should not be included in the all " \
                      "property response since it has security restrictions.")
 
+    def test_renderAllProperties_unauthorized_included(self):
+        # If we request to render all properties, and request to render a
+        # property we ain't authorized via the 'include' element then we
+        # should get the property back as part of the multistatus response
+        # but with a status 401 and no content.
+        resource = Resource("some text", 10)
+        request = zope.webdav.publisher.WebDAVRequest(StringIO(""), {})
+        propf = PROPFIND(None, request)
 
+        etree = component.getUtility(IEtree)
+        includes = etree.fromstring("""<include xmlns="DAV:" xmlns:D="DAVtest:">
+<D:unauthprop />
+</include>""")
+
+        response = propf.renderAllProperties(resource, request, includes)
+        response = response()
+
+        self.assertEqual(len(response.findall("{DAV:}propstat")), 2)
+
+        self.assertMSPropertyValue(
+            response, "{DAVtest:}unauthprop", status = 401)
+
+    def test_renderAllProperties_broken_included(self):
+        # If we request to render all properties, and to forse render a
+        # broken property via the 'include' element then we should get
+        # this property back as part of the multistatus response but with a
+        # status 500 and no content.
+        resource = Resource("some text", 10)
+        request = zope.webdav.publisher.WebDAVRequest(StringIO(""), {})
+        propf = PROPFIND(None, request)
+
+        etree = component.getUtility(IEtree)
+        includes = etree.fromstring("""<include xmlns="DAV:" xmlns:D="DAVtest:">
+<D:brokenprop />
+</include>""")
+
+        response = propf.renderAllProperties(resource, request, includes)
+        response = response()
+
+        self.assertEqual(len(response.findall("{DAV:}propstat")), 2)
+
+        self.assertMSPropertyValue(
+            response, "{DAVtest:}brokenprop", status = 500)
+
+        self.assertEqual(len(self.errUtility.errors), 1)
+        exc_info = self.errUtility.errors[0]
+        self.assertEqual(isinstance(exc_info[0][1], NotImplementedError), True)
+
+
 class PROPFINDRecuseTest(unittest.TestCase):
 
     def setUp(self):



More information about the Checkins mailing list