[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