def test_renderPrivileges(self): """ Verify that a directory listing includes children which you don't have access to. """ request = SimpleRequest(self.site, "GET", "/") def setEmptyACL(resource): resource.setAccessControlList(davxml.ACL()) # Empty ACL = no access return resource def renderRoot(_): d = request.locateResource("/") d.addCallback(lambda r: r.render(request)) return d def assertListing(response): data = [] d = readStream(response.stream, lambda s: data.append(str(s))) d.addCallback(lambda _: self.failIf( 'dir2/' not in "".join(data), "'dir2' expected in listing: %r" % (data,) )) return d d = request.locateResource("/dir2") d.addCallback(setEmptyACL) d.addCallback(renderRoot) d.addCallback(assertListing) return d
def work(): for method in ("GET", "REPORT"): if method == "GET": ok = responsecode.OK elif method == "REPORT": ok = responsecode.MULTI_STATUS else: raise AssertionError("We shouldn't be here. (method = %r)" % (method,)) for name, code in ( ("none" , responsecode.FORBIDDEN), ("read" , ok), ("read-write" , ok), ("unlock" , responsecode.FORBIDDEN), ("all" , ok), ): path = os.path.join(self.docroot, name) request = SimpleRequest(self.site, method, "/" + name) if method == "REPORT": request.stream = MemoryStream(element.PrincipalPropertySearch().toxml()) _add_auth_header(request) def test(response, code=code, path=path): if response.code != code: return self.oops(request, response, code, method, name) yield (request, test)
def test_Quota_Bad_Adjustment(self): """ Quota adjustment too much """ dst_uri = "/dst" def checkPUTResult(response): response = IResponse(response) if response.code != responsecode.CREATED: self.fail("Incorrect response code for PUT (%s != %s)" % (response.code, responsecode.CREATED)) def doBadAdjustment(_ignore): def checkAdjustmentResult(_ignore): return self.checkQuota(100) d = self.site.resource.quotaSizeAdjust(None, -200) d.addCallback(checkAdjustmentResult) return d d = self.checkQuota(100) d.addCallback(doBadAdjustment) return d request = SimpleRequest(self.site, "PUT", dst_uri) request.stream = FileStream(file(os.path.join(os.path.dirname(__file__), "data", "quota_100.txt"), "rb")) return self.send(request, checkPUTResult)
def work(): for code in ( responsecode.CREATED, responsecode.PRECONDITION_FAILED, responsecode.NO_CONTENT, responsecode.PRECONDITION_FAILED, responsecode.NO_CONTENT, responsecode.CREATED, ): def checkResult(response, code=code): response = IResponse(response) if response.code != code: self.fail("Incorrect response code for PUT (%s != %s)" % (response.code, code)) def onError(f): f.trap(HTTPError) return checkResult(f.value.response) request = SimpleRequest(self.site, "PUT", dst_uri) request.stream = FileStream(file(__file__, "rb")) if code == responsecode.CREATED: if os.path.isfile(dst_path): os.remove(dst_path) request.headers.setHeader("if-none-match", ("*",)) elif code == responsecode.PRECONDITION_FAILED: request.headers.setHeader("if-none-match", ("*",)) yield (request, (checkResult, onError))
def _simple_PROPPATCH(self, patch, prop, expected_code, what): def check_result(response): response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("Incorrect response code for PROPPATCH (%s != %s)" % (response.code, responsecode.MULTI_STATUS)) return davXMLFromStream(response.stream).addCallback(check_xml) def check_xml(doc): response = doc.root_element.childOfType(davxml.Response) propstat = response.childOfType(davxml.PropertyStatus) self.failUnless( response.childOfType(davxml.HRef) == "/", "Incorrect response URI: %s != /" % (response.childOfType(davxml.HRef),) ) self.failIf( propstat.childOfType(davxml.PropertyContainer).childOfType(prop) is None, "Not a %s in PROPPATCH property status: %s" % (prop.sname(), propstat.toxml()) ) self.failUnless( propstat.childOfType(davxml.Status).code == expected_code, "Incorrect status code for PROPPATCH %s: %s != %s" % (what, propstat.childOfType(davxml.Status).code, expected_code) ) request = SimpleRequest(self.site, "PROPPATCH", "/") request.stream = MemoryStream(patch.toxml()) return self.send(request, check_result)
def test_free_busy_set_same(self): """ Test that calendar-free-busy-set has the correct value and can be reset to the same. """ request = SimpleRequest(self.site, "GET", "/calendars/users/user01/inbox/") inbox = yield request.locateResource("/calendars/users/user01/inbox/") self.assertTrue((yield inbox.hasProperty(caldavxml.CalendarFreeBusySet, request))) prop = (yield inbox.readProperty(caldavxml.CalendarFreeBusySet, request)) self.assertEqual(prop.children[0], davxml.HRef("/calendars/__uids__/user01/calendar/")) newfbset = set() newfbset.add("/calendars/users/user01/calendar/") newset = caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in newfbset]) yield inbox.writeProperty(newset, request) yield request._newStoreTransaction.commit() request = SimpleRequest(self.site, "GET", "/calendars/users/user01/inbox/") inbox = yield request.locateResource("/calendars/users/user01/inbox/") prop = (yield inbox.readProperty(caldavxml.CalendarFreeBusySet, request)) self.assertEqual(prop.children[0], davxml.HRef("/calendars/__uids__/user01/calendar/")) yield request._newStoreTransaction.commit() calendar = yield request.locateResource("/calendars/__uids__/user01/calendar/") self.assertTrue(calendar._newStoreObject.isUsedForFreeBusy())
def _checkPrivileges(self, resource, url, principal, privilege, allowed): request = SimpleRequest(self.site, "GET", "/") def gotResource(resource): d = resource.checkPrivileges( request, (privilege,), principal=davxml.Principal(principal) ) if allowed: def onError(f): f.trap(AccessDeniedError) # print(resource.readDeadProperty(davxml.ACL)) self.fail( "%s should have %s privilege on %r" % (principal.sname(), privilege.sname(), resource) ) d.addErrback(onError) else: def expectAccessDenied(f): f.trap(AccessDeniedError) def onSuccess(_): # print(resource.readDeadProperty(davxml.ACL)) self.fail( "%s should not have %s privilege on %r" % (principal.sname(), privilege.sname(), resource) ) d.addCallbacks(onSuccess, expectAccessDenied) return d d = request.locateResource(url) d.addCallback(gotResource) return d
def test_Quota_DELETE(self): """ Quota change on DELETE """ dst_uri = "/dst" def checkPUTResult(response): response = IResponse(response) if response.code != responsecode.CREATED: self.fail("Incorrect response code for PUT (%s != %s)" % (response.code, responsecode.CREATED)) def doDelete(_ignore): def checkDELETEResult(response): response = IResponse(response) if response.code != responsecode.NO_CONTENT: self.fail("Incorrect response code for PUT (%s != %s)" % (response.code, responsecode.NO_CONTENT)) return self.checkQuota(0) request = SimpleRequest(self.site, "DELETE", dst_uri) return self.send(request, checkDELETEResult) d = self.checkQuota(100) d.addCallback(doDelete) return d request = SimpleRequest(self.site, "PUT", dst_uri) request.stream = FileStream(file(os.path.join(os.path.dirname(__file__), "data", "quota_100.txt"), "rb")) return self.send(request, checkPUTResult)
def work(): for which in (davxml.AllProperties(), davxml.PropertyName()): query = davxml.PropertyFind(which) request = SimpleRequest(self.site, "PROPFIND", "/") request.headers.setHeader("depth", "0") request.stream = MemoryStream(query.toxml()) yield (request, check_result(which))
def test_REPORT_no_body(self): """ REPORT request with no body """ def do_test(response): response = IResponse(response) if response.code != responsecode.BAD_REQUEST: self.fail("Unexpected response code for REPORT with no body: %s" % (response.code,)) request = SimpleRequest(self.site, "REPORT", "/") request.stream = MemoryStream("") return self.send(request, do_test)
def test_receive_ping(self): """ Cross-pod request works with the "ping" action. """ request = SimpleRequest(self.site, "POST", "/conduit", headers=http_headers.Headers( rawHeaders={ "Content-Type": ("application/json", ), self.thisServer.secretHeader()[0]: self.thisServer.secretHeader()[1], }), content=""" { "action":"ping" } """.replace("\n", "\r\n")) response = (yield self.send(request)) self.assertEqual(response.code, responsecode.OK) data = (yield allDataFromStream(response.stream)) j = json.loads(data) self.assertTrue("result" in j) self.assertEqual(j["result"], "ok")
def test_REPORT_no_body(self): """ REPORT request with no body """ def do_test(response): response = IResponse(response) if response.code != responsecode.BAD_REQUEST: self.fail( "Unexpected response code for REPORT with no body: %s" % (response.code, )) request = SimpleRequest(self.site, "REPORT", "/") request.stream = MemoryStream("") return self.send(request, do_test)
def test_receive_fake_conduit(self): """ Cross-pod request works when conduit does support the action. """ store = self.storeUnderTest() self.patch(store, "conduit", self.FakeConduit(store)) request = SimpleRequest(self.site, "POST", "/conduit", headers=http_headers.Headers( rawHeaders={ "Content-Type": ("application/json", ), self.thisServer.secretHeader()[0]: self.thisServer.secretHeader()[1], }), content=""" { "action":"fake", "echo":"bravo" } """.replace("\n", "\r\n")) response = (yield self.send(request)) self.assertEqual(response.code, responsecode.OK) data = (yield allDataFromStream(response.stream)) j = json.loads(data) self.assertTrue("result" in j) self.assertEqual(j["result"], "ok") self.assertTrue("value" in j) self.assertEqual(j["value"], {"back2u": "bravo", "more": "bits"})
def test_receive_fake_conduit_no_action(self): """ Cross-pod request fails when conduit does not support the action. """ store = self.storeUnderTest() self.patch(store, "conduit", self.FakeConduit(store)) request = SimpleRequest(self.site, "POST", "/conduit", headers=http_headers.Headers( rawHeaders={ "Content-Type": ("application/json", ), self.thisServer.secretHeader()[0]: self.thisServer.secretHeader()[1], }), content=""" { "action":"bogus", "echo":"bravo" } """.replace("\n", "\r\n")) response = (yield self.send(request)) self.assertEqual(response.code, responsecode.BAD_REQUEST)
def test_free_busy_set_invalid_url(self): """ Test that calendar-free-busy-set will generate an error if an invalid value is used. """ request = SimpleRequest(self.site, "GET", "/calendars/users/user01/inbox/") inbox = yield request.locateResource("/calendars/users/user01/inbox/") self.assertTrue((yield inbox.hasProperty(caldavxml.CalendarFreeBusySet, request))) oldfbset = set(("/calendar",)) newfbset = set() newfbset.update(oldfbset) newfbset.add("/calendar-broken") newset = caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in newfbset]) yield self.failUnlessFailure(inbox.writeProperty(newset, request), HTTPError)
def test_lacksPrivileges(self): request = SimpleRequest(self.site, "GET", "/protected") request.headers.setHeader( "authorization", ("basic", "baduser:badpass".encode("base64"))) d = self.assertFailure(self.checkSecurity(request), HTTPError) d.addCallback(self.assertErrorResponse, responsecode.FORBIDDEN) return d
def test_dav_header_full_caldav(self): """ DAV header advertises CalDAV """ def do_test(response): response = IResponse(response) dav = response.headers.getHeader("dav") if not dav: self.fail("no DAV header: %s" % (response.headers, )) self.assertIn("1", dav, "no DAV level 1 header") self.assertIn("access-control", dav, "no DAV access-control header") self.assertIn("calendar-access", dav, "no DAV calendar-access header") self.assertIn("calendar-schedule", dav, "no DAV calendar-schedule header") self.assertIn("calendar-auto-schedule", dav, "no DAV calendar-auto-schedule header") self.assertIn("calendar-availability", dav, "no DAV calendar-availability header") config.Scheduling.CalDAV.OldDraftCompatibility = True request = SimpleRequest(self.site, "OPTIONS", "/") return self.send(request, do_test)
def test_Header_Our_Server_Allowed(self): proxy = ReverseProxyResource("pool") proxy.allowMultiHop = True request = SimpleRequest(proxy, "GET", "/") request.headers.addRawHeader("x-forwarded-server", config.ServerHostName) response = yield proxy.renderHTTP(request) self.assertIsInstance(response, ClientRequest)
def work(): src_path = os.path.join(self.docroot, "read") uri = "/" + os.path.basename(src_path) for method in ("COPY", "MOVE"): for name, code in ( ("nobind" , responsecode.FORBIDDEN), ("bind" , responsecode.CREATED), ("unbind" , responsecode.CREATED), ): dst_parent_path = os.path.join(self.docroot, name) dst_path = os.path.join(dst_parent_path, "dst") request = SimpleRequest(self.site, method, uri) request.headers.setHeader("destination", "/" + name + "/dst") _add_auth_header(request) def test(response, code=code, dst_path=dst_path): if os.path.isfile(dst_path): os.remove(dst_path) if response.code != code: return self.oops(request, response, code, method, name) yield (request, test) self.restore()
def test_PUT_no_parent(self): """ PUT with no parent """ dst_uri = "/put/no/parent" def checkResult(response): response = IResponse(response) if response.code != responsecode.CONFLICT: self.fail("Incorrect response code for PUT with no parent (%s != %s)" % (response.code, responsecode.CONFLICT)) request = SimpleRequest(self.site, "PUT", dst_uri) request.stream = FileStream(file(__file__, "rb")) return self.send(request, checkResult)
def test_findChildrenWithPrivileges(self): """ This test revokes read privileges for the C{"/file2"} and C{"/dir2/"} resource to verify that we can not find them giving our unauthenticated privileges. """ expected_children = [ "/file1", "/dir1/", ] request = SimpleRequest(self.site, "GET", "/") resource = waitForDeferred(request.locateResource("/")) yield resource resource = resource.getResult() def checkChildren(resource, uri): self.assertEquals(uri, resource.uri) if uri not in expected_children: unexpected_children.append(uri) else: found_children.append(uri) found_children = [] unexpected_children = [] privileges = waitForDeferred(resource.currentPrivileges(request)) yield privileges privileges = privileges.getResult() fc = resource.findChildren("1", request, checkChildren, privileges) completed = waitForDeferred(fc) yield completed completed.getResult() self.assertEquals( unexpected_children, [], "Found unexpected children: %r" % (unexpected_children,) ) expected_children.sort() found_children.sort() self.assertEquals(expected_children, found_children)
def test_Header_Other_Servers(self): proxy = ReverseProxyResource("pool") request = SimpleRequest(proxy, "GET", "/") request.headers.setHeader("x-forwarded-server", ( "foobar.example.com", "bar.example.com", )) self.assertIsInstance(proxy.renderHTTP(request), ClientRequest)
def test_locateChild(self): resource = LeafResource() child, segments = (resource.locateChild( SimpleRequest(Site(resource), "GET", "/"), ("", "foo"), )) self.assertEquals(child, resource) self.assertEquals(segments, StopTraversal)
def test_isOwnerYes_noStoreObject(self): """ L{CalDAVResource.isOwner} returns C{True} for authenticated requests with a principal that matches the resource's owner. """ site = None request = SimpleRequest(site, "GET", "/not/a/real/url/") request.authzUser = request.authnUser = StubPrincipal("/yes-i-am-the-owner/") parent = CalDAVResource() parent.owner = lambda igreq: HRef("/yes-i-am-the-owner/") rsrc = CalDAVResource() rsrc._newStoreObject = None request._rememberResource(parent, "/not/a/real/") request._rememberResource(rsrc, "/not/a/real/url/") self.assertEquals((yield rsrc.isOwner(request)), True)
def test_checkPrivileges(self): """ DAVResource.checkPrivileges() """ ds = [] authAllResource = AuthAllResource() requested_access = (davxml.All(),) site = Site(authAllResource) def expectError(failure): failure.trap(AccessDeniedError) errors = failure.value.errors self.failUnless(len(errors) == 1) subpath, denials = errors[0] self.failUnless(subpath is None) self.failUnless( tuple(denials) == requested_access, "%r != %r" % (tuple(denials), requested_access) ) def expectOK(result): self.failUnlessEquals(result, None) def _checkPrivileges(resource): d = resource.checkPrivileges(request, requested_access) return d # No auth; should deny request = SimpleRequest(site, "GET", "/") d = request.locateResource("/").addCallback(_checkPrivileges).addErrback(expectError) ds.append(d) # Has auth; should allow request = SimpleRequest(site, "GET", "/") request.authzUser = request.authnUser = self.rootresource.principalForUser("gooduser") d = request.locateResource("/") d.addCallback(_checkPrivileges) d.addCallback(expectOK) ds.append(d) return DeferredList(ds)
def test_free_busy_set_same(self): """ Test that calendar-free-busy-set has the correct value and can be reset to the same. """ request = SimpleRequest(self.site, "GET", "/calendars/users/user01/inbox/") inbox = yield request.locateResource("/calendars/users/user01/inbox/") self.assertTrue((yield inbox.hasProperty(caldavxml.CalendarFreeBusySet, request))) prop = (yield inbox.readProperty(caldavxml.CalendarFreeBusySet, request)) self.assertEqual(prop.children[0], davxml.HRef("/calendars/__uids__/user01/calendar/")) newfbset = set() newfbset.add("/calendars/users/user01/calendar/") newset = caldavxml.CalendarFreeBusySet( *[davxml.HRef(url) for url in newfbset]) yield inbox.writeProperty(newset, request) yield request._newStoreTransaction.commit() request = SimpleRequest(self.site, "GET", "/calendars/users/user01/inbox/") inbox = yield request.locateResource("/calendars/users/user01/inbox/") prop = (yield inbox.readProperty(caldavxml.CalendarFreeBusySet, request)) self.assertEqual(prop.children[0], davxml.HRef("/calendars/__uids__/user01/calendar/")) yield request._newStoreTransaction.commit() calendar = yield request.locateResource( "/calendars/__uids__/user01/calendar/") self.assertTrue(calendar._newStoreObject.isUsedForFreeBusy())
def test_findChildrenWithPrivileges(self): """ This test revokes read privileges for the C{"/file2"} and C{"/dir2/"} resource to verify that we can not find them giving our unauthenticated privileges. """ expected_children = [ "/file1", "/dir1/", ] request = SimpleRequest(self.site, "GET", "/") resource = waitForDeferred(request.locateResource("/")) yield resource resource = resource.getResult() def checkChildren(resource, uri): self.assertEquals(uri, resource.uri) if uri not in expected_children: unexpected_children.append(uri) else: found_children.append(uri) found_children = [] unexpected_children = [] privileges = waitForDeferred(resource.currentPrivileges(request)) yield privileges privileges = privileges.getResult() fc = resource.findChildren("1", request, checkChildren, privileges) completed = waitForDeferred(fc) yield completed completed.getResult() self.assertEquals( unexpected_children, [], "Found unexpected children: %r" % (unexpected_children, )) expected_children.sort() found_children.sort() self.assertEquals(expected_children, found_children)
def test_Header_Our_Server_Moxied(self): proxy = ReverseProxyResource("pool") request = SimpleRequest(proxy, "GET", "/") request.headers.setHeader("x-forwarded-server", ( "foobar.example.com", "bar.example.com", config.ServerHostName, )) yield self.assertFailure(proxy.renderHTTP(request), HTTPError)
def test_Quota_PUT(self): """ Quota change on PUT """ dst_uri = "/dst" def checkResult(response): response = IResponse(response) if response.code != responsecode.CREATED: self.fail("Incorrect response code for PUT (%s != %s)" % (response.code, responsecode.CREATED)) return self.checkQuota(100) request = SimpleRequest(self.site, "PUT", dst_uri) request.stream = FileStream(file(os.path.join(os.path.dirname(__file__), "data", "quota_100.txt"), "rb")) return self.send(request, checkResult)
def test_failsWithDifferentMethod(self): """ Test that the response fails if made for a different request method than it is being issued for. """ d = self._createAndDecodeChallenge(req=SimpleRequest(None, 'POST', '/')) def _test(creds): self.failIf(creds.checkPassword('password')) return d.addCallback(_test)
def test_okLink(self): resource = CalendarHomeResource(self.site.resource, "home", object(), StubHome()) self.site.resource.putChild("home", resource) link = LinkResource(resource, "/home/outbox/") resource.putChild("link", link) request = SimpleRequest(self.site, "GET", "/home/link/") linked_to, _ignore = (yield resource.locateChild(request, ["link", ])) self.assertTrue(linked_to is resource.getChild("outbox"))
def work(): dst_uri = "/dst" for name in os.listdir(self.docroot): if name == "dst": continue path = os.path.join(self.docroot, name) # Can't really PUT something you can't read if not os.path.isfile(path): continue def do_test(response): checkResult(response, path) request = SimpleRequest(self.site, "PUT", dst_uri) request.stream = FileStream(file(path, "rb")) yield (request, do_test)
def test_renderHTTP(self): """ Test that if the renderHTTP method is ever called we authenticate the request and delegate rendering to the wrapper. """ self.protectedResource.responseText = "I hope you can see me." self.protectedResource.addSlash = True root = wrapper.HTTPAuthResource(self.protectedResource, [self.credFactory], self.portal, interfaces=(IHTTPUser, )) request = SimpleRequest(None, "GET", "/") request.prepath = [''] def _gotSecondResponse(response): self.assertEquals(response.code, 200) self.assertEquals(str(response.stream.read()), "I hope you can see me.") def _gotResponse(exception): response = exception.response self.assertEquals(response.code, 401) self.failUnless(response.headers.hasHeader('WWW-Authenticate')) self.assertEquals(response.headers.getHeader('WWW-Authenticate'), [('basic', { 'realm': "test realm" })]) credentials = base64.encodestring('username:password') request.headers.setHeader('authorization', ['basic', credentials]) d = root.renderHTTP(request) d.addCallback(_gotSecondResponse) d = self.assertFailure(root.renderHTTP(request), http.HTTPError) d.addCallback(_gotResponse) return d
def test_REPORT_unknown(self): """ Unknown/bogus report type """ def do_test(response): response = IResponse(response) if response.code != responsecode.FORBIDDEN: self.fail("Unexpected response code for unknown REPORT: %s" % (response.code,)) class GoofyReport (davxml.WebDAVUnknownElement): namespace = "GOOFY:" name = "goofy-report" def __init__(self): super(GoofyReport, self).__init__() request = SimpleRequest(self.site, "REPORT", "/") request.stream = MemoryStream(GoofyReport().toxml()) return self.send(request, do_test)
def test_renderHTTP(self): """ Test that if the renderHTTP method is ever called we authenticate the request and delegate rendering to the wrapper. """ self.protectedResource.responseText = "I hope you can see me." self.protectedResource.addSlash = True root = wrapper.HTTPAuthResource(self.protectedResource, [self.credFactory], self.portal, interfaces=(IHTTPUser,)) request = SimpleRequest(None, "GET", "/") request.prepath = [''] def _gotSecondResponse(response): self.assertEquals(response.code, 200) self.assertEquals(str(response.stream.read()), "I hope you can see me.") def _gotResponse(exception): response = exception.response self.assertEquals(response.code, 401) self.failUnless(response.headers.hasHeader('WWW-Authenticate')) self.assertEquals(response.headers.getHeader('WWW-Authenticate'), [('basic', {'realm': "test realm"})]) credentials = base64.encodestring('username:password') request.headers.setHeader('authorization', ['basic', credentials]) d = root.renderHTTP(request) d.addCallback(_gotSecondResponse) d = self.assertFailure(root.renderHTTP(request), http.HTTPError) d.addCallback(_gotResponse) return d
def test_free_busy_set_invalid_url(self): """ Test that calendar-free-busy-set will generate an error if an invalid value is used. """ request = SimpleRequest(self.site, "GET", "/calendars/users/user01/inbox/") inbox = yield request.locateResource("/calendars/users/user01/inbox/") self.assertTrue((yield inbox.hasProperty(caldavxml.CalendarFreeBusySet, request))) oldfbset = set(("/calendar", )) newfbset = set() newfbset.update(oldfbset) newfbset.add("/calendar-broken") newset = caldavxml.CalendarFreeBusySet( *[davxml.HRef(url) for url in newfbset]) self.failUnlessFailure(inbox.writeProperty(newset, request), HTTPError)
def test_authorize(self): """ Authorizing a known user with the correct password will not raise an exception, indicating that the user is properly authorized given their credentials. """ request = SimpleRequest(self.site, "GET", "/protected") request.headers.setHeader( "authorization", ("basic", "gooduser:goodpass".encode("base64"))) return self.checkSecurity(request)
def test_isOwnerUnauthenticated(self): """ L{CalDAVResource.isOwner} returns C{False} for unauthenticated requests. """ site = None request = SimpleRequest(site, "GET", "/not/a/real/url/") request.authzUser = request.authnUser = None rsrc = CalDAVResource() rsrc.owner = lambda igreq: HRef("/somebody/") self.assertEquals((yield rsrc.isOwner(request)), False)
def test_findChildrenCallbackRaises(self): """ Verify that when the user callback raises an exception the completion deferred returned by findChildren errbacks TODO: Verify that the user callback doesn't get called subsequently """ def raiseOnChild(resource, uri): raise Exception("Oh no!") def findChildren(resource): return self.assertFailure( resource.findChildren("infinity", request, raiseOnChild), Exception) request = SimpleRequest(self.site, "GET", "/") d = request.locateResource("/").addCallback(findChildren) return d
def test_checkPreconditions_none(self): """ RenderMixin.checkPreconditions() checkPreconditions() returns None """ resource = TestResource() request = SimpleRequest(Site(resource), "SWEETHOOKUPS", "/") # Check that checkPreconditions without a raise doesn't barf self.assertEquals((yield resource.renderHTTP(request)), responsecode.NO_CONTENT)
def test_isOwnerYes(self): """ L{CalDAVResource.isOwner} returns C{True} for authenticated requests with a principal that matches the resource's owner. """ site = None request = SimpleRequest(site, "GET", "/not/a/real/url/") request.authzUser = request.authnUser = StubPrincipal("/yes-i-am-the-owner/") rsrc = CalDAVResource() rsrc.owner = lambda igreq: HRef("/yes-i-am-the-owner/") self.assertEquals((yield rsrc.isOwner(request)), True)
def test_badLink(self): resource = CalendarHomeResource(self.site.resource, "home", object(), StubHome()) self.site.resource.putChild("home", resource) link = LinkResource(resource, "/home/outbox/abc") resource.putChild("link", link) request = SimpleRequest(self.site, "GET", "/home/link/") try: yield resource.locateChild(request, ["link", ]) except HTTPError, e: self.assertEqual(e.response.code, responsecode.NOT_FOUND)
def test_receive_reject_local_originator(self): """ Make calendar """ request = SimpleRequest( self.site, "POST", "/ischedule", headers=http_headers.Headers( rawHeaders={ "Originator": ("mailto:[email protected]", ), "Recipient": ("mailto:[email protected]", ), "Content-Type": ("text/calendar", ) }), content="""BEGIN:VCALENDAR CALSCALE:GREGORIAN PRODID:-//Example Inc.//Example Calendar//EN VERSION:2.0 METHOD:REQUEST BEGIN:VEVENT DTSTAMP:20051222T205953Z CREATED:20060101T150000Z DTSTART:20060101T100000Z DURATION:PT1H SUMMARY:event 1 UID:deadlocked ORGANIZER:mailto:[email protected] ATTENDEE;PARTSTAT=ACCEPTED:mailto:[email protected] ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:[email protected] END:VEVENT END:VCALENDAR """.replace("\n", "\r\n")) response = (yield self.send(request)) self.assertEqual(response.code, responsecode.FORBIDDEN) calendar = (yield self.calendarUnderTest(name="calendar_1", home="user01")) count = (yield calendar.listCalendarObjects()) self.assertEqual(len(count), 0) inbox = (yield self.calendarUnderTest(name="inbox", home="user01")) count = (yield inbox.listCalendarObjects()) self.assertEqual(len(count), 0) calendar = (yield self.calendarUnderTest(name="calendar_1", home="user02")) count = (yield calendar.listCalendarObjects()) self.assertEqual(len(count), 0) inbox = (yield self.calendarUnderTest(name="inbox", home="user02")) count = (yield inbox.listCalendarObjects()) self.assertEqual(len(count), 0)
def _test_level(self, level): def doTest(response): response = IResponse(response) dav = response.headers.getHeader("dav") if not dav: self.fail("no DAV header: %s" % (response.headers, )) self.assertIn(level, dav, "no DAV level %s header" % (level, )) return response return self.send(SimpleRequest(self.site, "OPTIONS", "/"), doTest)
def test_Quota_PUT(self): """ Quota change on PUT """ dst_uri = "/dst" self.site.resource.setQuotaRoot(None, 90) def checkResult(response): response = IResponse(response) if response.code != responsecode.INSUFFICIENT_STORAGE_SPACE: self.fail("Incorrect response code for PUT (%s != %s)" % (response.code, responsecode.INSUFFICIENT_STORAGE_SPACE)) return self.checkQuota(0) request = SimpleRequest(self.site, "PUT", dst_uri) request.stream = FileStream(file(os.path.join(os.path.dirname(__file__), "data", "quota_100.txt"), "rb")) return self.send(request, checkResult)
def work(): dst_path = os.path.join(self.docroot, "copy_dst") dst_uri = "/" + os.path.basename(dst_path) for src, status in ( ("nobind", responsecode.FORBIDDEN), ("bind", responsecode.FORBIDDEN), ("unbind", responsecode.CREATED), ): src_path = os.path.join(self.docroot, "src_" + src) src_uri = "/" + os.path.basename(src_path) if not os.path.isdir(src_path): os.mkdir(src_path) src_resource = self.resource_class(src_path) src_resource.setAccessControlList({ "nobind": self.grant(), "bind" : self.grant(element.Bind()), "unbind": self.grant(element.Bind(), element.Unbind()) }[src]) for name, acl in ( ("none" , self.grant()), ("read" , self.grant(element.Read())), ("read-write" , self.grant(element.Read(), element.Write())), ("unlock" , self.grant(element.Unlock())), ("all" , self.grant(element.All())), ): filename = os.path.join(src_path, name) if not os.path.isfile(filename): file(filename, "w").close() self.resource_class(filename).setAccessControlList(acl) for method in ("COPY", "MOVE"): for name, code in ( ("none", {"COPY": responsecode.FORBIDDEN, "MOVE": status}[method]), ("read", {"COPY": responsecode.CREATED, "MOVE": status}[method]), ("read-write" , {"COPY": responsecode.CREATED, "MOVE": status}[method]), ("unlock", {"COPY": responsecode.FORBIDDEN, "MOVE": status}[method]), ("all", {"COPY": responsecode.CREATED, "MOVE": status}[method]), ): path = os.path.join(src_path, name) uri = src_uri + "/" + name request = SimpleRequest(self.site, method, uri) request.headers.setHeader("destination", dst_uri) _add_auth_header(request) def test(response, code=code, path=path): if os.path.isfile(dst_path): os.remove(dst_path) if response.code != code: return self.oops(request, response, code, method, name) yield (request, test)
def work(): for name, code in ( ("none" , responsecode.FORBIDDEN), ("read" , responsecode.FORBIDDEN), ("read-write" , responsecode.MULTI_STATUS), ("unlock" , responsecode.FORBIDDEN), ("all" , responsecode.MULTI_STATUS), ): path = os.path.join(self.docroot, name) request = SimpleRequest(self.site, "PROPPATCH", "/" + name) request.stream = MemoryStream( element.WebDAVDocument(element.PropertyUpdate()).toxml() ) _add_auth_header(request) def test(response, code=code, path=path): if response.code != code: return self.oops(request, response, code, "PROPPATCH", name) yield (request, test)
def test_findChildrenCallbackRaises(self): """ Verify that when the user callback raises an exception the completion deferred returned by findChildren errbacks TODO: Verify that the user callback doesn't get called subsequently """ def raiseOnChild(resource, uri): raise Exception("Oh no!") def findChildren(resource): return self.assertFailure( resource.findChildren("infinity", request, raiseOnChild), Exception ) request = SimpleRequest(self.site, "GET", "/") d = request.locateResource("/").addCallback(findChildren) return d
def test_free_busy_set_tasks(self): """ Test that calendar-free-busy-set ignores tasks calendar. """ request = SimpleRequest(self.site, "GET", "/calendars/users/user01/inbox/") inbox = yield request.locateResource("/calendars/users/user01/inbox/") self.assertTrue((yield inbox.hasProperty(caldavxml.CalendarFreeBusySet, request))) prop = (yield inbox.readProperty(caldavxml.CalendarFreeBusySet, request)) self.assertEqual( set([str(child) for child in prop.children]), set(( "/calendars/__uids__/user01/calendar/", )) ) newfbset = set() newfbset.add("/calendars/users/user01/tasks/") newset = caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in newfbset]) yield inbox.writeProperty(newset, request) yield request._newStoreTransaction.commit() request = SimpleRequest(self.site, "GET", "/calendars/users/user01/inbox/") inbox = yield request.locateResource("/calendars/users/user01/inbox/") prop = (yield inbox.readProperty(caldavxml.CalendarFreeBusySet, request)) self.assertEqual(len(prop.children), 0) yield request._newStoreTransaction.commit() calendar = yield request.locateResource("/calendars/__uids__/user01/tasks/") self.assertFalse(calendar._newStoreObject.isUsedForFreeBusy()) calendar = yield request.locateResource("/calendars/__uids__/user01/calendar/") self.assertFalse(calendar._newStoreObject.isUsedForFreeBusy())
def free_busy_query(self, calendar_uri, query, got_calendar): request = SimpleRequest(self.site, "MKCALENDAR", calendar_uri) response = yield self.send(request) response = IResponse(response) if response.code != responsecode.CREATED: self.fail("MKCALENDAR failed: %s" % (response.code,)) yield addEventsDir(self, FilePath(self.holidays_dir), calendar_uri) request = SimpleRequest(self.site, "REPORT", calendar_uri) request.stream = MemoryStream(query.toxml()) response = yield self.send(request) response = IResponse(response) if response.code != responsecode.OK: self.fail("REPORT failed: %s" % (response.code,)) result = yield Component.fromIStream(response.stream).addCallback( got_calendar ) returnValue(result)
def test_MKCOL_invalid_body(self): """ MKCOL request with invalid request body (Any body at all is invalid in our implementation; there is no such thing as a valid body.) """ path, uri = self.mkdtemp("collection") rmdir(path) def check_result(response): response = IResponse(response) if response.code != responsecode.UNSUPPORTED_MEDIA_TYPE: self.fail("MKCOL response %s != %s" % (response.code, responsecode.UNSUPPORTED_MEDIA_TYPE)) if os.path.isdir(path): self.fail("MKCOL incorrectly created directory %s" % (path,)) request = SimpleRequest(self.site, "MKCOL", uri) request.stream = MemoryStream("This is not a valid MKCOL request body.") return self.send(request, check_result)
def test_free_busy_set_different(self): """ Test that calendar-free-busy-set has the correct value and can be reset to the same. """ txn = self.transactionUnderTest() home = (yield txn.calendarHomeWithUID("user01", create=True)) yield home.createCalendarWithName("calendar_new") yield self.commit() request = SimpleRequest(self.site, "GET", "/calendars/users/user01/inbox/") inbox = yield request.locateResource("/calendars/users/user01/inbox/") self.assertTrue((yield inbox.hasProperty(caldavxml.CalendarFreeBusySet, request))) prop = (yield inbox.readProperty(caldavxml.CalendarFreeBusySet, request)) self.assertEqual( set([str(child) for child in prop.children]), set(( "/calendars/__uids__/user01/calendar/", "/calendars/__uids__/user01/calendar_new/", )) ) calendar = yield request.locateResource("/calendars/__uids__/user01/calendar_new/") self.assertTrue(calendar._newStoreObject.isUsedForFreeBusy()) calendar = yield request.locateResource("/calendars/__uids__/user01/calendar/") self.assertTrue(calendar._newStoreObject.isUsedForFreeBusy()) newfbset = set() newfbset.add("/calendars/users/user01/calendar_new/") newset = caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in newfbset]) yield inbox.writeProperty(newset, request) yield request._newStoreTransaction.commit() request = SimpleRequest(self.site, "GET", "/calendars/users/user01/inbox/") inbox = yield request.locateResource("/calendars/users/user01/inbox/") prop = (yield inbox.readProperty(caldavxml.CalendarFreeBusySet, request)) self.assertEqual(prop.children[0], davxml.HRef("/calendars/__uids__/user01/calendar_new/")) yield request._newStoreTransaction.commit() calendar = yield request.locateResource("/calendars/__uids__/user01/calendar_new/") self.assertTrue(calendar._newStoreObject.isUsedForFreeBusy()) calendar = yield request.locateResource("/calendars/__uids__/user01/calendar/") self.assertFalse(calendar._newStoreObject.isUsedForFreeBusy())
def test_PROPFIND_basic(self): """ PROPFIND request """ def check_result(response): response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("Incorrect response code for PROPFIND (%s != %s)" % (response.code, responsecode.MULTI_STATUS)) content_type = response.headers.getHeader("content-type") if content_type not in (http_headers.MimeType("text", "xml"), http_headers.MimeType("application", "xml")): self.fail("Incorrect content-type for PROPFIND response (%r not in %r)" % (content_type, (http_headers.MimeType("text", "xml"), http_headers.MimeType("application", "xml")))) return davXMLFromStream(response.stream).addCallback(check_xml) def check_xml(doc): multistatus = doc.root_element if not isinstance(multistatus, davxml.MultiStatus): self.fail("PROPFIND response XML root element is not multistatus: %r" % (multistatus,)) for response in multistatus.childrenOfType(davxml.PropertyStatusResponse): if response.childOfType(davxml.HRef) == "/": for propstat in response.childrenOfType(davxml.PropertyStatus): status = propstat.childOfType(davxml.Status) properties = propstat.childOfType(davxml.PropertyContainer).children if status.code != responsecode.OK: self.fail("PROPFIND failed (status %s) to locate live properties: %s" % (status.code, properties)) properties_to_find = [p.qname() for p in self.liveProperties()] for property in properties: qname = property.qname() if qname in properties_to_find: properties_to_find.remove(qname) else: self.fail("PROPFIND found property we didn't ask for: %r" % (property,)) if properties_to_find: self.fail("PROPFIND failed to find properties: %r" % (properties_to_find,)) break else: self.fail("No response for URI /") query = davxml.PropertyFind(davxml.PropertyContainer(*self.liveProperties())) request = SimpleRequest(self.site, "PROPFIND", "/") depth = "1" if depth is not None: request.headers.setHeader("depth", depth) request.stream = MemoryStream(query.toxml()) return self.send(request, check_result)
def test_findChildren(self): """ This test asserts that we have: 1) not found any unexpected children 2) found all expected children It does this for all depths C{"0"}, C{"1"}, and C{"infintiy"} """ expected_children = { "0": [], "1": [ "/file1", "/file2", "/dir1/", "/dir2/", ], "infinity": [ "/file1", "/file2", "/dir1/", "/dir1/subdir1/", "/dir2/", "/dir2/file1", "/dir2/file2", "/dir2/subdir1/", "/dir2/subdir1/file1", "/dir2/subdir1/file2", ], } request = SimpleRequest(self.site, "GET", "/") resource = waitForDeferred(request.locateResource("/")) yield resource resource = resource.getResult() def checkChildren(resource, uri): self.assertEquals(uri, resource.uri) if uri not in expected_children[depth]: unexpected_children.append(uri) else: found_children.append(uri) for depth in ["0", "1", "infinity"]: found_children = [] unexpected_children = [] fc = resource.findChildren(depth, request, checkChildren) completed = waitForDeferred(fc) yield completed completed.getResult() self.assertEquals( unexpected_children, [], "Found unexpected children: %r" % (unexpected_children,) ) expected_children[depth].sort() found_children.sort() self.assertEquals(expected_children[depth], found_children)
def test_PROPPATCH_basic(self): """ PROPPATCH """ # FIXME: # Do PROPFIND to make sure it's still there # Test nonexistant resource # Test None namespace in property def check_patch_response(response): response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("Incorrect response code for PROPFIND (%s != %s)" % (response.code, responsecode.MULTI_STATUS)) content_type = response.headers.getHeader("content-type") if content_type not in (http_headers.MimeType("text", "xml"), http_headers.MimeType("application", "xml")): self.fail("Incorrect content-type for PROPPATCH response (%r not in %r)" % (content_type, (http_headers.MimeType("text", "xml"), http_headers.MimeType("application", "xml")))) return davXMLFromStream(response.stream).addCallback(check_patch_xml) def check_patch_xml(doc): multistatus = doc.root_element if not isinstance(multistatus, davxml.MultiStatus): self.fail("PROPFIND response XML root element is not multistatus: %r" % (multistatus,)) # Requested a property change one resource, so there should be exactly one response response = multistatus.childOfType(davxml.Response) # Should have a response description (its contents are arbitrary) response.childOfType(davxml.ResponseDescription) # Requested property change was on / self.failUnless( response.childOfType(davxml.HRef) == "/", "Incorrect response URI: %s != /" % (response.childOfType(davxml.HRef),) ) # Requested one property change, so there should be exactly one property status propstat = response.childOfType(davxml.PropertyStatus) # And the contained property should be a SpiffyProperty self.failIf( propstat.childOfType(davxml.PropertyContainer).childOfType(SpiffyProperty) is None, "Not a SpiffyProperty in PROPPATCH property status: %s" % (propstat.toxml()) ) # And the status should be 200 self.failUnless( propstat.childOfType(davxml.Status).code == responsecode.OK, "Incorrect status code for PROPPATCH of property %s: %s != %s" % (propstat.childOfType(davxml.PropertyContainer).toxml(), propstat.childOfType(davxml.Status).code, responsecode.OK) ) patch = davxml.PropertyUpdate( davxml.Set( davxml.PropertyContainer( SpiffyProperty.fromString("This is a spiffy resource.") ) ) ) request = SimpleRequest(self.site, "PROPPATCH", "/") request.stream = MemoryStream(patch.toxml()) return self.send(request, check_patch_response)