def test_wikiACL(self): """ Ensure shareeAccessControlList( ) honors the access granted by the wiki to the sharee, so that delegates of the sharee get the same level of access. """ sharedName = yield self.wikiSetup() access = WikiAccessLevel.read def stubAccessForRecord(*args): return succeed(access) self.patch(WikiDirectoryRecord, "accessForRecord", stubAccessForRecord) request = SimpleStoreRequest(self, "GET", "/calendars/__uids__/user01/") collection = yield request.locateResource("/calendars/__uids__/user01/" + sharedName) # Simulate the wiki server granting Read access acl = (yield collection.shareeAccessControlList(request)) self.assertFalse("<write/>" in acl.toxml()) # Simulate the wiki server granting Read-Write access access = WikiAccessLevel.write acl = (yield collection.shareeAccessControlList(request)) self.assertTrue("<write/>" in acl.toxml())
def addEventsDir(testCase, eventsDir, uri): """ Add events to a L{twistedcaldav.test.util.TestCase} from a directory. @param testCase: The test case to add events to. @type testCase: L{twistedcaldav.test.util.TestCase} @param eventsDir: A directory full of events. @type eventsDir: L{FilePath} @param uri: The URI-path of the calendar to insert events into. @type uri: C{str} @return: a L{Deferred} which fires with the number of added calendar object resources. """ count = 0 for child in eventsDir.children(): count += 1 if child.basename().split(".")[-1] != "ics": continue request = SimpleStoreRequest(testCase, "PUT", uri + "/" + child.basename()) request.stream = MemoryStream(child.getContent()) yield testCase.send(request) returnValue(count)
def test_wikiACL(self): """ Ensure shareeAccessControlList( ) honors the access granted by the wiki to the sharee, so that delegates of the sharee get the same level of access. """ sharedName = yield self.wikiSetup() access = WikiAccessLevel.read def stubAccessForRecord(*args): return succeed(access) self.patch(WikiDirectoryRecord, "accessForRecord", stubAccessForRecord) request = SimpleStoreRequest(self, "GET", "/calendars/__uids__/user01/") collection = yield request.locateResource( "/calendars/__uids__/user01/" + sharedName) # Simulate the wiki server granting Read access acl = (yield collection.shareeAccessControlList(request)) self.assertFalse("<write/>" in acl.toxml()) # Simulate the wiki server granting Read-Write access access = WikiAccessLevel.write acl = (yield collection.shareeAccessControlList(request)) self.assertTrue("<write/>" in acl.toxml())
def test_fail_dot_file_put_in_calendar(self): """ Make (regular) collection in calendar """ calendar_uri = "/calendars/users/wsanchez/dot_file_in_calendar/" principal = yield self.actualRoot.findPrincipalForAuthID("wsanchez") request = SimpleStoreRequest(self, "MKCALENDAR", calendar_uri, authPrincipal=principal) response = yield self.send(request) response = IResponse(response) if response.code != responsecode.CREATED: self.fail("MKCALENDAR failed: %s" % (response.code,)) stream = self.dataPath.child( "Holidays").child( "C318AA54-1ED0-11D9-A5E0-000A958A3252.ics" ).open() try: calendar = str(Component.fromStream(stream)) finally: stream.close() event_uri = "/".join([calendar_uri, ".event.ics"]) request = SimpleStoreRequest(self, "PUT", event_uri, authPrincipal=principal) request.headers.setHeader("content-type", MimeType("text", "calendar")) request.stream = MemoryStream(calendar) response = yield self.send(request) response = IResponse(response) if response.code != responsecode.FORBIDDEN: self.fail("Incorrect response to dot file PUT: %s" % (response.code,))
def test_timeoutOnPUT(self): """ PUT gets a 503 on a lock timeout. """ # Create a fake lock txn = self.transactionUnderTest() yield NamedLock.acquire(txn, "ImplicitUIDLock:%s" % (hashlib.md5("uid1").hexdigest(),)) # PUT fails principal = yield self.actualRoot.findPrincipalForAuthID("wsanchez") request = SimpleStoreRequest( self, "PUT", "/calendars/users/wsanchez/calendar/1.ics", headers=Headers({"content-type": MimeType.fromString("text/calendar")}), authPrincipal=principal ) request.stream = MemoryStream("""BEGIN:VCALENDAR CALSCALE:GREGORIAN PRODID:-//Apple Computer\, Inc//iCal 2.0//EN VERSION:2.0 BEGIN:VEVENT UID:uid1 DTSTART;VALUE=DATE:20020101 DTEND;VALUE=DATE:20020102 DTSTAMP:20020101T121212Z SUMMARY:New Year's Day END:VEVENT END:VCALENDAR """.replace("\n", "\r\n")) response = yield self.send(request) self.assertEqual(response.code, responsecode.SERVICE_UNAVAILABLE)
def test_set_default_vevent_other(self): """ Test that the default URL can be set to another VEVENT calendar """ request = SimpleStoreRequest(self, "GET", "/calendars/users/wsanchez/") inbox = yield request.locateResource("/calendars/users/wsanchez/inbox") # default property is present default = yield inbox.readProperty(caldavxml.ScheduleDefaultCalendarURL, request) self.assertEqual(str(default.children[0]), "/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar") # Create a new default calendar newcalendar = yield request.locateResource("/calendars/users/wsanchez/newcalendar") yield newcalendar.createCalendarCollection() yield newcalendar.setSupportedComponents(("VEVENT",)) yield self.commit() request = SimpleStoreRequest(self, "GET", "/calendars/users/wsanchez/") inbox = yield request.locateResource("/calendars/users/wsanchez/inbox") yield inbox.writeProperty(caldavxml.ScheduleDefaultCalendarURL(davxml.HRef("/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/newcalendar")), request) default = yield inbox.readProperty(caldavxml.ScheduleDefaultCalendarURL, request) self.assertEqual(str(default.children[0]), "/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/newcalendar") yield self.commit()
def test_fail_dot_file_put_in_calendar(self): """ Make (regular) collection in calendar """ calendar_uri = "/calendars/users/wsanchez/dot_file_in_calendar/" principal = yield self.actualRoot.findPrincipalForAuthID("wsanchez") request = SimpleStoreRequest(self, "MKCALENDAR", calendar_uri, authPrincipal=principal) response = yield self.send(request) response = IResponse(response) if response.code != responsecode.CREATED: self.fail("MKCALENDAR failed: %s" % (response.code, )) stream = self.dataPath.child("Holidays").child( "C318AA54-1ED0-11D9-A5E0-000A958A3252.ics").open() try: calendar = str(Component.fromStream(stream)) finally: stream.close() event_uri = "/".join([calendar_uri, ".event.ics"]) request = SimpleStoreRequest(self, "PUT", event_uri, authPrincipal=principal) request.headers.setHeader("content-type", MimeType("text", "calendar")) request.stream = MemoryStream(calendar) response = yield self.send(request) response = IResponse(response) if response.code != responsecode.FORBIDDEN: self.fail("Incorrect response to dot file PUT: %s" % (response.code, ))
def test_is_default_calendar(self): """ Test .isDefaultCalendar() returns the proper class or None. """ # Create a new non-default calendar request = SimpleStoreRequest(self, "GET", "/calendars/users/wsanchez/") newcalendar = yield request.locateResource( "/calendars/users/wsanchez/newcalendar") yield newcalendar.createCalendarCollection() yield newcalendar.setSupportedComponents(("VEVENT", )) inbox = yield request.locateResource("/calendars/users/wsanchez/inbox") yield inbox.defaultCalendar(request, "VEVENT") yield inbox.defaultCalendar(request, "VTODO") yield self.commit() request = SimpleStoreRequest(self, "GET", "/calendars/users/wsanchez/") inbox = yield request.locateResource("/calendars/users/wsanchez/inbox") calendar = yield request.locateResource( "/calendars/users/wsanchez/calendar") newcalendar = yield request.locateResource( "/calendars/users/wsanchez/newcalendar") tasks = yield request.locateResource("/calendars/users/wsanchez/tasks") result = yield calendar.isDefaultCalendar(request) self.assertTrue(result) result = yield newcalendar.isDefaultCalendar(request) self.assertFalse(result) result = yield tasks.isDefaultCalendar(request) self.assertTrue(result) yield self.commit()
def _test_file_in_calendar(self, what, *work): """ Creates a calendar collection, then PUTs a resource into that collection with the data from given stream and verifies that the response code from the PUT request matches the given response_code. """ calendar_uri = "/calendars/users/wsanchez/testing_calendar/" principal = yield self.actualRoot.findPrincipalForAuthID("wsanchez") request = SimpleStoreRequest(self, "MKCALENDAR", calendar_uri, authPrincipal=principal) response = yield self.send(request) response = IResponse(response) if response.code != responsecode.CREATED: self.fail("MKCALENDAR failed: %s" % (response.code,)) c = 0 for stream, response_code in work: dst_uri = joinURL(calendar_uri, "dst%d.ics" % (c,)) request = SimpleStoreRequest(self, "PUT", dst_uri, authPrincipal=principal) request.headers.setHeader("if-none-match", "*") request.headers.setHeader("content-type", MimeType("text", "calendar")) request.stream = stream response = yield self.send(request) response = IResponse(response) if response.code != response_code: self.fail("Incorrect response to %s: %s (!= %s)" % (what, response.code, response_code)) c += 1
def test_missing_default_vtodo_calendar(self): """ Test that readProperty will not create a missing default calendar. """ request = SimpleStoreRequest(self, "GET", "/calendars/users/wsanchez/") home = yield request.locateResource("/calendars/users/wsanchez/") inbox = yield request.locateResource("/calendars/users/wsanchez/inbox") # default property present default = yield inbox.readProperty(customxml.ScheduleDefaultTasksURL, request) self.assertEqual( str(default.children[0]), "/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/tasks") # Forcibly remove the one we need yield home._newStoreHome.removeChildWithName("tasks") names = [ calendarName for calendarName in (yield home._newStoreHome.listCalendars()) ] self.assertTrue("tasks" not in names) # Property is empty now default = yield inbox.readProperty(customxml.ScheduleDefaultTasksURL, request) self.assertEqual(len(default.children), 0) yield self.abort()
def test_pick_default_addressbook(self): """ Get adbk """ request = SimpleStoreRequest(self, "GET", "/addressbooks/users/wsanchez/", authPrincipal=self.authPrincipal) home = yield request.locateResource("/addressbooks/users/wsanchez") # default property initially not present try: home.readDeadProperty(carddavxml.DefaultAddressBookURL) except HTTPError: pass else: self.fail("carddavxml.DefaultAddressBookURL is not empty") yield home.pickNewDefaultAddressBook(request) try: default = home.readDeadProperty(carddavxml.DefaultAddressBookURL) except HTTPError: self.fail("carddavxml.DefaultAddressBookURL is not present") else: self.assertEqual( str(default.children[0]), "/addressbooks/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/addressbook/" )
def mkcalendar_cb(response): response = IResponse(response) if response.code != responsecode.CREATED: self.fail("MKCALENDAR failed: %s" % (response.code,)) def put_cb(response): response = IResponse(response) if response.code != responsecode.FORBIDDEN: self.fail("Incorrect response to dot file PUT: %s" % (response.code,)) stream = self.dataPath.child( "Holidays").child( "C318AA54-1ED0-11D9-A5E0-000A958A3252.ics" ).open() try: calendar = str(Component.fromStream(stream)) finally: stream.close() event_uri = "/".join([calendar_uri, ".event.ics"]) request = SimpleStoreRequest(self, "PUT", event_uri, authid="wsanchez") request.headers.setHeader("content-type", MimeType("text", "calendar")) request.stream = MemoryStream(calendar) return self.send(request, put_cb)
def test_collection_in_calendar(self): """ Make (regular) collection in calendar """ calendar_uri = "/calendars/users/wsanchez/collection_in_calendar/" principal = yield self.actualRoot.findPrincipalForAuthID("wsanchez") request = SimpleStoreRequest(self, "MKCALENDAR", calendar_uri, authPrincipal=principal) response = yield self.send(request) response = IResponse(response) if response.code != responsecode.CREATED: self.fail("MKCALENDAR failed: %s" % (response.code, )) nested_uri = joinURL(calendar_uri, "nested") request = SimpleStoreRequest(self, "MKCOL", nested_uri, authPrincipal=principal) response = yield self.send(request) response = IResponse(response) if response.code != responsecode.FORBIDDEN: self.fail("Incorrect response to nested MKCOL: %s" % (response.code, ))
def calendar_query(self, calendar_uri, query, got_xml, data, no_init): if not no_init: response = yield self.send( SimpleStoreRequest(self, "MKCALENDAR", calendar_uri, authPrincipal=self.authPrincipal)) response = IResponse(response) if response.code != responsecode.CREATED: self.fail("MKCALENDAR failed: %s" % (response.code, )) if data: for filename, icaldata in data.iteritems(): request = SimpleStoreRequest( self, "PUT", joinURL(calendar_uri, filename + ".ics"), headers=Headers({ "content-type": MimeType.fromString("text/calendar") }), authPrincipal=self.authPrincipal) request.stream = MemoryStream(icaldata) yield self.send(request) else: # Add holiday events to calendar for child in FilePath(self.holidays_dir).children(): if os.path.splitext(child.basename())[1] != ".ics": continue request = SimpleStoreRequest( self, "PUT", joinURL(calendar_uri, child.basename()), headers=Headers({ "content-type": MimeType.fromString("text/calendar") }), authPrincipal=self.authPrincipal) request.stream = MemoryStream(child.getContent()) yield self.send(request) request = SimpleStoreRequest(self, "REPORT", calendar_uri, authPrincipal=self.authPrincipal) request.stream = MemoryStream(query.toxml()) response = yield self.send(request) response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("REPORT failed: %s" % (response.code, )) returnValue((yield davXMLFromStream(response.stream).addCallback(got_xml)))
def test_pick_default_vtodo_calendar(self): """ Test that pickNewDefaultCalendar will choose the correct tasks calendar. """ request = SimpleStoreRequest(self, "GET", "/calendars/users/wsanchez/") inbox = yield request.locateResource("/calendars/users/wsanchez/inbox") default = yield inbox.readProperty(customxml.ScheduleDefaultTasksURL, request) self.assertEqual(str(default.children[0]), "/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/tasks") yield self.abort()
def test_pick_default_vevent_calendar(self): """ Test that pickNewDefaultCalendar will choose the correct calendar. """ request = SimpleStoreRequest(self, "GET", "/calendars/users/wsanchez/") inbox = yield request.locateResource("/calendars/users/wsanchez/inbox") # default property initially present prop = yield inbox.readProperty(caldavxml.ScheduleDefaultCalendarURL, request) self.assertEqual(str(prop.children[0]), "/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar") yield self.abort()
def requestForPath(self, path, method='GET'): """ Get a L{Request} with a L{FakeChanRequest} for a given path and method. """ headers = Headers() headers.addRawHeader("Host", "localhost:8008") req = SimpleStoreRequest(self, method, path, headers) # 'process()' normally sets these. Shame on web2, having so much # partially-initialized stuff floating around. req.remoteAddr = '127.0.0.1' req.chanRequest = FakeChanRequest() req.credentialFactories = {} return req
def test_is_default_calendar(self): """ Test .isDefaultCalendar() returns the proper class or None. """ # Create a new non-default calendar request = SimpleStoreRequest(self, "GET", "/calendars/users/wsanchez/") newcalendar = yield request.locateResource("/calendars/users/wsanchez/newcalendar") yield newcalendar.createCalendarCollection() yield newcalendar.setSupportedComponents(("VEVENT",)) inbox = yield request.locateResource("/calendars/users/wsanchez/inbox") yield inbox.defaultCalendar(request, "VEVENT") yield inbox.defaultCalendar(request, "VTODO") yield self.commit() request = SimpleStoreRequest(self, "GET", "/calendars/users/wsanchez/") inbox = yield request.locateResource("/calendars/users/wsanchez/inbox") calendar = yield request.locateResource("/calendars/users/wsanchez/calendar") newcalendar = yield request.locateResource("/calendars/users/wsanchez/newcalendar") tasks = yield request.locateResource("/calendars/users/wsanchez/tasks") result = yield calendar.isDefaultCalendar(request) self.assertTrue(result) result = yield newcalendar.isDefaultCalendar(request) self.assertFalse(result) result = yield tasks.isDefaultCalendar(request) self.assertTrue(result) yield self.commit()
def calendar_query(self, query, got_xml): request = SimpleStoreRequest(self, "REPORT", "/calendars/users/wsanchez/calendar/", authid="wsanchez") request.stream = MemoryStream(query.toxml()) response = yield self.send(request) response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("REPORT failed: %s" % (response.code,)) returnValue( (yield davXMLFromStream(response.stream).addCallback(got_xml)) )
def test_pick_default_vtodo_calendar(self): """ Test that pickNewDefaultCalendar will choose the correct tasks calendar. """ request = SimpleStoreRequest(self, "GET", "/calendars/users/wsanchez/") inbox = yield request.locateResource("/calendars/users/wsanchez/inbox") default = yield inbox.readProperty(customxml.ScheduleDefaultTasksURL, request) self.assertEqual( str(default.children[0]), "/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/tasks") yield self.abort()
def test_failedPodChildRetry(self): """ Test that a cross-pod error during an HTTP request results in a 503 error with a Retry-After header. """ # Patch request handling to raise an exception def _objectResourceWithName(self, name): raise FailedCrossPodRequestError() self.patch(Calendar, "objectResourceWithName", _objectResourceWithName) self.patch(self.store, "timeoutTransactions", 1) # Run delayed request authPrincipal = yield self.actualRoot.findPrincipalForAuthID("user01") request = SimpleStoreRequest( self, "GET", "/calendars/__uids__/user01/calendar/1.ics", authPrincipal=authPrincipal) try: yield self.send(request) except HTTPError as e: self.assertEqual(e.response.code, responsecode.SERVICE_UNAVAILABLE) self.assertTrue(e.response.headers.hasHeader("Retry-After")) self.assertApproximates( int(e.response.headers.getRawHeaders("Retry-After")[0]), config.TransactionHTTPRetrySeconds, 1) else: self.fail("HTTPError not raised")
def test_conduitRetry(self): """ Test that a cross-pod error during an HTTP request results in a 503 error with a Retry-After header. """ # Patch request handling to raise an exception def _iCalendarRolledup(self, request): raise FailedCrossPodRequestError() self.patch(CalendarCollectionResource, "iCalendarRolledup", _iCalendarRolledup) self.patch(self.store, "timeoutTransactions", 1) # Run delayed request authPrincipal = yield self.actualRoot.findPrincipalForAuthID("user01") request = SimpleStoreRequest(self, "GET", "/calendars/__uids__/user01/calendar/", authPrincipal=authPrincipal) response = yield self.send(request) self.assertEqual(response.code, responsecode.SERVICE_UNAVAILABLE) self.assertTrue(response.headers.hasHeader("Retry-After")) self.assertApproximates( int(response.headers.getRawHeaders("Retry-After")[0]), config.TransactionHTTPRetrySeconds, 1)
def test_inSacls(self): """ Test the behavior of locateChild when SACLs are enabled and the user is in the SACL group should return a valid resource """ self.actualRoot.useSacls = True principal = yield self.actualRoot.findPrincipalForAuthID("dreid") request = SimpleStoreRequest(self, "GET", "/principals/", authPrincipal=principal) resrc, segments = (yield maybeDeferred(self.actualRoot.locateChild, request, ["principals"])) self.failUnless( isinstance(resrc, DirectoryPrincipalProvisioningResource), "Did not get a DirectoryPrincipalProvisioningResource: %s" % (resrc, )) self.assertEquals(segments, []) self.assertEquals( request.authzUser.principalElement(), davxml.Principal( davxml.HRef( "/principals/__uids__/5FF60DAD-0BDE-4508-8C77-15F0CA5C8DD1/" )))
def test_timeoutRetry(self): """ Test that a timed out transaction during an HTTP request results in a 503 error with a Retry-After header. """ # Patch request handling to add a delay to trigger the txn time out original = CalendarCollectionResource.iCalendarRolledup @inlineCallbacks def _iCalendarRolledup(self, request): d = Deferred() reactor.callLater(2, d.callback, None) yield d result = yield original(self, request) returnValue(result) self.patch(CalendarCollectionResource, "iCalendarRolledup", _iCalendarRolledup) self.patch(self.store, "timeoutTransactions", 1) # Run delayed request authPrincipal = yield self.actualRoot.findPrincipalForAuthID("user01") request = SimpleStoreRequest(self, "GET", "/calendars/__uids__/user01/calendar/", authPrincipal=authPrincipal) try: yield self.send(request) except HTTPError as e: self.assertEqual(e.response.code, responsecode.SERVICE_UNAVAILABLE) self.assertTrue(e.response.headers.hasHeader("Retry-After")) self.assertApproximates(int(e.response.headers.getRawHeaders("Retry-After")[0]), config.TransactionHTTPRetrySeconds, 1) else: self.fail("HTTPError not raised")
def test_notInSacls(self): """ Test the behavior of locateChild when SACLs are enabled and the user is not in the SACL group should return a 403 forbidden response """ self.actualRoot.useSacls = True principal = yield self.actualRoot.findPrincipalForAuthID("wsanchez") request = SimpleStoreRequest( self, "GET", "/principals/", authPrincipal=principal ) try: _ignore_resrc, _ignore_segments = (yield maybeDeferred( self.actualRoot.locateChild, request, ["principals"] )) raise AssertionError( "RootResource.locateChild did not return an error" ) except HTTPError, e: self.assertEquals(e.response.code, 403)
def test_make_calendar_in_calendar(self): """ Make calendar in calendar """ first_uri = "/calendars/users/user01/calendar_in_calendar/" @inlineCallbacks def next(response): response = IResponse(response) if response.code != responsecode.CREATED: self.fail("MKCALENDAR failed: %s" % (response.code, )) def do_test(response): response = IResponse(response) if response.code != responsecode.FORBIDDEN: self.fail("Incorrect response to nested MKCALENDAR: %s" % (response.code, )) nested_uri = os.path.join(first_uri, "nested") request = SimpleStoreRequest(self, "MKCALENDAR", nested_uri, authPrincipal=self.authPrincipal) yield self.send(request, do_test) request = SimpleStoreRequest(self, "MKCALENDAR", first_uri, authPrincipal=self.authPrincipal) return self.send(request, next)
def test_make_calendar(self): """ Make calendar """ uri = "/calendars/users/user01/calendar_make/" path = os.path.join(self.docroot, uri[1:]) if os.path.exists(path): rmdir(path) request = SimpleStoreRequest(self, "MKCALENDAR", uri, authPrincipal=self.authPrincipal) @inlineCallbacks def do_test(response): response = IResponse(response) if response.code != responsecode.CREATED: self.fail("Incorrect response to successful MKCALENDAR: %s" % (response.code, )) resource = (yield request.locateResource(uri)) if not resource: self.fail("MKCALENDAR made no calendar") if not resource.isCalendarCollection(): self.fail("MKCALENDAR made non-calendar collection") return self.send(request, do_test)
def test_badCredentials(self): """ Test the behavior of locateChild when SACLS are enabled, and incorrect credentials are given. should return a 401 UnauthorizedResponse """ self.actualRoot.useSacls = True request = SimpleStoreRequest( self, "GET", "/principals/", headers=http_headers.Headers( { "Authorization": [ "basic", "%s" % ("dreid:dreid".encode("base64"),) ] } ) ) try: _ignore_resrc, _ignore_segments = (yield maybeDeferred( self.actualRoot.locateChild, request, ["principals"] )) raise AssertionError( "RootResource.locateChild did not return an error" ) except HTTPError, e: self.assertEquals(e.response.code, 401)
def test_pick_default_vevent_calendar(self): """ Test that pickNewDefaultCalendar will choose the correct calendar. """ request = SimpleStoreRequest(self, "GET", "/calendars/users/wsanchez/") inbox = yield request.locateResource("/calendars/users/wsanchez/inbox") # default property initially present prop = yield inbox.readProperty(caldavxml.ScheduleDefaultCalendarURL, request) self.assertEqual( str(prop.children[0]), "/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar" ) yield self.abort()
def calendar_query(self, query, got_xml): principal = yield self.actualRoot.findPrincipalForAuthID("wsanchez") request = SimpleStoreRequest(self, "REPORT", "/calendars/users/wsanchez/calendar/", authPrincipal=principal) request.stream = MemoryStream(query.toxml()) response = yield self.send(request) response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("REPORT failed: %s" % (response.code, )) returnValue((yield davXMLFromStream(response.stream).addCallback(got_xml)))
def test_PROPFIND(self): self.actualRoot.useSacls = True body = """<?xml version="1.0" encoding="utf-8" ?> <D:propfind xmlns:D="DAV:"> <D:prop> <D:getetag/> <D:displayname/> </D:prop> </D:propfind> """ principal = yield self.actualRoot.findPrincipalForAuthID("dreid") request = SimpleStoreRequest( self, "PROPFIND", "/principals/users/dreid/", headers=http_headers.Headers({ 'Depth': '1', }), authPrincipal=principal, content=body ) response = yield self.send(request) response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("Incorrect response for PROPFIND /principals/: %s" % (response.code,)) request = SimpleStoreRequest( self, "PROPFIND", "/principals/users/dreid/", headers=http_headers.Headers({ 'Depth': '1', }), authPrincipal=principal, content=body ) response = yield self.send(request) response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("Incorrect response for PROPFIND /principals/: %s" % (response.code,)) self.assertEqual(self.actualRoot.responseCache.cacheHitCount, 1)
def test_DELETE(self): def do_test(response): response = IResponse(response) if response.code != responsecode.FORBIDDEN: self.fail("Incorrect response for DELETE /: %s" % (response.code,)) request = SimpleStoreRequest(self, "DELETE", "/") return self.send(request, do_test)
def test_oneTime(self): """ Make sure wiki auth lookup is only done once per request; request.checkedWiki will be set to True """ request = SimpleStoreRequest(self, "GET", "/principals/") _ignore_resrc, _ignore_segments = (yield maybeDeferred( self.actualRoot.locateChild, request, ["principals"])) self.assertTrue(request.checkedWiki)
def calendar_query(self, query, got_xml, expected_code=responsecode.MULTI_STATUS): principal = yield self.actualRoot.findPrincipalForAuthID("wsanchez") request = SimpleStoreRequest(self, "REPORT", "/calendars/users/wsanchez/calendar/", authPrincipal=principal) request.stream = MemoryStream(query.toxml()) response = yield self.send(request) response = IResponse(response) if response.code != expected_code: self.fail("REPORT failed: %s" % (response.code,)) if got_xml is not None: returnValue( (yield davXMLFromStream(response.stream).addCallback(got_xml)) ) else: returnValue( (yield allDataFromStream(response.stream)) )
def test_POSTShareeRemoveWithMissingSharer(self): yield self.resource.upgradeToShare() yield self._doPOST("""<?xml version="1.0" encoding="utf-8" ?> <CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/"> <CS:set> <D:href>mailto:[email protected]</D:href> <CS:summary>My Shared Calendar</CS:summary> <CS:read-write/> </CS:set> </CS:share> """) propInvite = (yield self.resource.readProperty(customxml.Invite, None)) uid = self._getUIDElementValue(propInvite) self.assertEquals( self._clearUIDElementValue(propInvite), customxml.Invite( customxml.InviteUser( customxml.UID.fromString(""), davxml.HRef.fromString("urn:x-uid:user02"), customxml.CommonName.fromString("User 02"), customxml.InviteAccess(customxml.ReadWriteAccess()), customxml.InviteStatusNoResponse(), ), )) result = (yield self._doPOSTSharerAccept( """<?xml version='1.0' encoding='UTF-8'?> <invite-reply xmlns='http://calendarserver.org/ns/'> <href xmlns='DAV:'>mailto:[email protected]</href> <invite-accepted/> <hosturl> <href xmlns='DAV:'>/calendars/__uids__/user01/calendar/</href> </hosturl> <in-reply-to>%s</in-reply-to> <summary>The Shared Calendar</summary> <common-name>User 02</common-name> <first-name>user</first-name> <last-name>02</last-name> </invite-reply> """ % (uid, ))) href = self._getHRefElementValue(result) + "/" yield self.directory.removeRecords( ((yield self.userUIDFromShortName("user01")), )) self.assertTrue((yield self.userUIDFromShortName("user01")) is None) resource = (yield self._getResourceSharer(href)) yield resource.removeShareeResource( SimpleStoreRequest(self, "DELETE", href)) resource = (yield self._getResourceSharer(href)) self.assertFalse(resource.exists())
def test_pick_default_other(self): """ Make calendar """ request = SimpleStoreRequest(self, "GET", "/calendars/users/wsanchez/") inbox = yield request.locateResource("/calendars/users/wsanchez/inbox") # default property present default = yield inbox.readProperty(caldavxml.ScheduleDefaultCalendarURL, request) self.assertEqual(str(default.children[0]), "/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar") # Create a new default calendar newcalendar = yield request.locateResource("/calendars/users/wsanchez/newcalendar") yield newcalendar.createCalendarCollection() yield inbox.writeProperty(caldavxml.ScheduleDefaultCalendarURL(davxml.HRef("/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/newcalendar")), request) # Delete the normal calendar calendar = yield request.locateResource("/calendars/users/wsanchez/calendar") yield calendar.storeRemove(request) yield self.commit() request = SimpleStoreRequest(self, "GET", "/calendars/users/wsanchez/") inbox = yield request.locateResource("/calendars/users/wsanchez/inbox") default = yield inbox.readProperty(caldavxml.ScheduleDefaultCalendarURL, request) self.assertEqual(str(default.children[0]), "/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/newcalendar") yield self.abort()
def calendar_query(self, calendar_uri, query, got_xml, data, no_init): if not no_init: response = yield self.send(SimpleStoreRequest(self, "MKCALENDAR", calendar_uri, authid="wsanchez")) response = IResponse(response) if response.code != responsecode.CREATED: self.fail("MKCALENDAR failed: %s" % (response.code,)) if data: for filename, icaldata in data.iteritems(): request = SimpleStoreRequest(self, "PUT", joinURL(calendar_uri, filename + ".ics"), authid="wsanchez") request.stream = MemoryStream(icaldata) yield self.send(request) else: # Add holiday events to calendar for child in FilePath(self.holidays_dir).children(): if os.path.splitext(child.basename())[1] != ".ics": continue request = SimpleStoreRequest(self, "PUT", joinURL(calendar_uri, child.basename()), authid="wsanchez") request.stream = MemoryStream(child.getContent()) yield self.send(request) request = SimpleStoreRequest(self, "REPORT", calendar_uri, authid="wsanchez") request.stream = MemoryStream(query.toxml()) response = yield self.send(request) response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("REPORT failed: %s" % (response.code,)) returnValue( (yield davXMLFromStream(response.stream).addCallback(got_xml)) )
def mkcalendar_cb(response): response = IResponse(response) if response.code != responsecode.CREATED: self.fail("MKCALENDAR failed: %s" % (response.code,)) c = 0 for stream, response_code in work: dst_uri = joinURL(calendar_uri, "dst%d.ics" % (c,)) request = SimpleStoreRequest(self, "PUT", dst_uri, authid="wsanchez") request.headers.setHeader("if-none-match", "*") request.headers.setHeader("content-type", MimeType("text", "calendar")) request.stream = stream response = yield self.send(request) response = IResponse(response) if response.code != response_code: self.fail("Incorrect response to %s: %s (!= %s)" % (what, response.code, response_code)) c += 1
def addressbook_query(self, addressbook_uri, query, got_xml): ''' FIXME: clear address book, possibly by removing mkcol = """<?xml version="1.0" encoding="utf-8" ?> <D:mkcol xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:carddav"> <D:set> <D:prop> <D:resourcetype><D:collection/><C:addressbook/></D:resourcetype> </D:prop> </D:set> </D:mkcol> """ response = yield self.send(SimpleStoreRequest(self, "MKCOL", addressbook_uri, content=mkcol, authid="wsanchez")) response = IResponse(response) if response.code != responsecode.CREATED: self.fail("MKCOL failed: %s" % (response.code,)) ''' principal = yield self.actualRoot.findPrincipalForAuthID("wsanchez") # Add vCards to addressbook for child in FilePath(self.vcards_dir).children(): if os.path.splitext(child.basename())[1] != ".vcf": continue request = SimpleStoreRequest( self, "PUT", joinURL(addressbook_uri, child.basename()), authPrincipal=principal ) request.stream = MemoryStream(child.getContent()) yield self.send(request) request = SimpleStoreRequest(self, "REPORT", addressbook_uri, authPrincipal=principal) request.stream = MemoryStream(query.toxml()) response = yield self.send(request) response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("REPORT failed: %s" % (response.code,)) returnValue((yield davXMLFromStream(response.stream).addCallback(got_xml)))
def addressbook_query(self, addressbook_uri, query, got_xml, data, no_init): if not no_init: ''' FIXME: clear address book, possibly by removing mkcol = """<?xml version="1.0" encoding="utf-8" ?> <D:mkcol xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:carddav"> <D:set> <D:prop> <D:resourcetype><D:collection/><C:addressbook/></D:resourcetype> </D:prop> </D:set> </D:mkcol> """ response = yield self.send(SimpleStoreRequest(self, "MKCOL", addressbook_uri, content=mkcol, authPrincipal=self.authPrincipal)) response = IResponse(response) if response.code != responsecode.CREATED: self.fail("MKCOL failed: %s" % (response.code,)) ''' if data: for filename, icaldata in data.iteritems(): request = SimpleStoreRequest( self, "PUT", joinURL(addressbook_uri, filename + ".vcf"), headers=Headers({"content-type": MimeType.fromString("text/vcard")}), authPrincipal=self.authPrincipal ) request.stream = MemoryStream(icaldata) yield self.send(request) else: # Add vcards to addressbook for child in FilePath(self.vcards_dir).children(): if os.path.splitext(child.basename())[1] != ".vcf": continue request = SimpleStoreRequest( self, "PUT", joinURL(addressbook_uri, child.basename()), headers=Headers({"content-type": MimeType.fromString("text/vcard")}), authPrincipal=self.authPrincipal ) request.stream = MemoryStream(child.getContent()) yield self.send(request) request = SimpleStoreRequest(self, "REPORT", addressbook_uri, authPrincipal=self.authPrincipal) request.stream = MemoryStream(query.toxml()) response = yield self.send(request) response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("REPORT failed: %s" % (response.code,)) returnValue( (yield davXMLFromStream(response.stream).addCallback(got_xml)) )
def test_missing_default_vtodo_calendar(self): """ Test that readProperty will not create a missing default calendar. """ request = SimpleStoreRequest(self, "GET", "/calendars/users/wsanchez/") home = yield request.locateResource("/calendars/users/wsanchez/") inbox = yield request.locateResource("/calendars/users/wsanchez/inbox") # default property present default = yield inbox.readProperty(customxml.ScheduleDefaultTasksURL, request) self.assertEqual(str(default.children[0]), "/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/tasks") # Forcibly remove the one we need yield home._newStoreHome.removeChildWithName("tasks") names = [calendarName for calendarName in (yield home._newStoreHome.listCalendars())] self.assertTrue("tasks" not in names) # Property is empty now default = yield inbox.readProperty(customxml.ScheduleDefaultTasksURL, request) self.assertEqual(len(default.children), 0) yield self.abort()
def test_MOVE(self): def do_test(response): response = IResponse(response) if response.code != responsecode.FORBIDDEN: self.fail("Incorrect response for MOVE /: %s" % (response.code, )) request = SimpleStoreRequest(self, "MOVE", "/", headers=http_headers.Headers( {"Destination": "/copy/"})) return self.send(request, do_test)
def issueRequest(self, segments, method="GET"): """ Get a resource from a particular path from the root URI, and return a Deferred which will fire with (something adaptable to) an HTTP response object. """ request = SimpleStoreRequest(self, method, ("/".join([""] + segments))) rsrc = self.actualRoot while segments: rsrc, segments = (yield maybeDeferred(rsrc.locateChild, request, segments)) result = yield rsrc.renderHTTP(request) returnValue(result)
def test_wikiACL(self): """ Ensure shareeAccessControlList( ) honors the access granted by the wiki to the sharee, so that delegates of the sharee get the same level of access. """ access = "read" def stubWikiAccessMethod(userID, wikiID): return access self.patch(sharing, "getWikiAccess", stubWikiAccessMethod) sharedName = yield self.wikiSetup() request = SimpleStoreRequest(self, "GET", "/calendars/__uids__/user01/") collection = yield request.locateResource("/calendars/__uids__/user01/" + sharedName) # Simulate the wiki server granting Read access acl = (yield collection.shareeAccessControlList(request)) self.assertFalse("<write/>" in acl.toxml()) # Simulate the wiki server granting Read-Write access access = "write" acl = (yield collection.shareeAccessControlList(request)) self.assertTrue("<write/>" in acl.toxml())
def test_pick_default_addressbook(self): """ Get adbk """ request = SimpleStoreRequest(self, "GET", "/addressbooks/users/wsanchez/", authPrincipal=self.authPrincipal) home = yield request.locateResource("/addressbooks/users/wsanchez") # default property initially not present try: home.readDeadProperty(carddavxml.DefaultAddressBookURL) except HTTPError: pass else: self.fail("carddavxml.DefaultAddressBookURL is not empty") yield home.pickNewDefaultAddressBook(request) try: default = home.readDeadProperty(carddavxml.DefaultAddressBookURL) except HTTPError: self.fail("carddavxml.DefaultAddressBookURL is not present") else: self.assertEqual(str(default.children[0]), "/addressbooks/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/addressbook/")
def test_make_calendar_on_collection(self): """ Make calendar on existing collection """ uri = "/calendars/users/user01/calendar/" def do_test(response): response = IResponse(response) if response.code != responsecode.FORBIDDEN: self.fail("Incorrect response to MKCALENDAR on existing resource: %s" % (response.code,)) # FIXME: Check for DAV:resource-must-be-null element request = SimpleStoreRequest(self, "MKCALENDAR", uri, authPrincipal=self.authPrincipal) return self.send(request, do_test)
def next(response): response = IResponse(response) if response.code != responsecode.CREATED: self.fail("MKCALENDAR failed: %s" % (response.code,)) def do_test(response): response = IResponse(response) if response.code != responsecode.FORBIDDEN: self.fail("Incorrect response to nested MKCALENDAR: %s" % (response.code,)) nested_uri = os.path.join(first_uri, "nested") request = SimpleStoreRequest(self, "MKCALENDAR", nested_uri, authPrincipal=self.authPrincipal) yield self.send(request, do_test)
def _getResourceSharer(self, name): request = SimpleStoreRequest(self, "GET", "%s" % (name,)) resource = yield request.locateResource("%s" % (name,)) returnValue(resource)
def mkcalendar_cb(response): response = IResponse(response) if response.code != responsecode.CREATED: self.fail("MKCALENDAR failed: %s" % (response.code,)) def propfind_cb(response): response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("Incorrect response to PROPFIND: %s" % (response.code,)) def got_xml(doc): if not isinstance(doc.root_element, davxml.MultiStatus): self.fail("PROPFIND response XML root element is not multistatus: %r" % (doc.root_element,)) response = doc.root_element.childOfType(davxml.Response) href = response.childOfType(davxml.HRef) self.failUnless(str(href) == calendar_uri) for propstat in response.childrenOfType(davxml.PropertyStatus): status = propstat.childOfType(davxml.Status) if status.code != responsecode.OK: self.fail("Unable to read requested properties (%s): %r" % (status, propstat.childOfType(davxml.PropertyContainer).toxml())) container = propstat.childOfType(davxml.PropertyContainer) # # Check CalDAV:supported-calendar-component-set # supported_components = container.childOfType(caldavxml.SupportedCalendarComponentSet) if not supported_components: self.fail("Expected CalDAV:supported-calendar-component-set element; but got none.") supported = set(("VEVENT",)) for component in supported_components.children: if component.type in supported: supported.remove(component.type) if supported: self.fail("Expected supported calendar component types: %s" % (tuple(supported),)) # # Check CalDAV:supported-calendar-data # supported_calendar = container.childOfType(caldavxml.SupportedCalendarData) if not supported_calendar: self.fail("Expected CalDAV:supported-calendar-data element; but got none.") for calendar in supported_calendar.children: if calendar.content_type not in ("text/calendar", "application/calendar+json"): self.fail("Expected a text/calendar calendar-data type restriction") if calendar.version != "2.0": self.fail("Expected a version 2.0 calendar-data restriction") # # Check DAV:supported-report-set # supported_reports = container.childOfType(davxml.SupportedReportSet) if not supported_reports: self.fail("Expected DAV:supported-report-set element; but got none.") cal_query = False cal_multiget = False cal_freebusy = False for supported in supported_reports.childrenOfType(davxml.SupportedReport): report = supported.childOfType(davxml.Report) if report.childOfType(caldavxml.CalendarQuery) is not None: cal_query = True if report.childOfType(caldavxml.CalendarMultiGet) is not None: cal_multiget = True if report.childOfType(caldavxml.FreeBusyQuery) is not None: cal_freebusy = True if not cal_query: self.fail("Expected CalDAV:CalendarQuery element; but got none.") if not cal_multiget: self.fail("Expected CalDAV:CalendarMultiGet element; but got none.") if not cal_freebusy: self.fail("Expected CalDAV:FreeBusyQuery element; but got none.") return davXMLFromStream(response.stream).addCallback(got_xml) query = davxml.PropertyFind( davxml.PropertyContainer( caldavxml.SupportedCalendarData(), caldavxml.SupportedCalendarComponentSet(), davxml.SupportedReportSet(), ), ) request = SimpleStoreRequest( self, "PROPFIND", calendar_uri, headers=http_headers.Headers({"Depth": "0"}), authPrincipal=self.authPrincipal, ) request.stream = MemoryStream(query.toxml()) return self.send(request, propfind_cb)
def mkcalendar_cb(response): response = IResponse(response) if response.code != responsecode.CREATED: self.fail("MKCALENDAR failed: %s" % (response.code,)) def propfind_cb(response): response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("Incorrect response to PROPFIND: %s" % (response.code,)) def got_xml(doc): if not isinstance(doc.root_element, davxml.MultiStatus): self.fail("PROPFIND response XML root element is not multistatus: %r" % (doc.root_element,)) response = doc.root_element.childOfType(davxml.Response) href = response.childOfType(davxml.HRef) self.failUnless(str(href) == calendar_uri) container = response.childOfType(davxml.PropertyStatus).childOfType(davxml.PropertyContainer) # # Check CalDAV:supported-calendar-component-set # supported_components = container.childOfType(caldavxml.SupportedCalendarComponentSet) if supported_components: self.fail("CalDAV:supported-calendar-component-set element was returned; but should be hidden.") # # Check CalDAV:supported-calendar-data # supported_calendar = container.childOfType(caldavxml.SupportedCalendarData) if supported_calendar: self.fail("CalDAV:supported-calendar-data elementwas returned; but should be hidden.") # # Check DAV:supported-report-set # supported_reports = container.childOfType(davxml.SupportedReportSet) if supported_reports: self.fail("DAV:supported-report-set element was returned; but should be hidden..") return davXMLFromStream(response.stream).addCallback(got_xml) query = davxml.PropertyFind( davxml.AllProperties(), ) request = SimpleStoreRequest( self, "PROPFIND", calendar_uri, headers=http_headers.Headers({"Depth": "0"}), authPrincipal=self.authPrincipal, ) request.stream = MemoryStream(query.toxml()) return self.send(request, propfind_cb)
def _getResource(self): request = SimpleStoreRequest(self, "GET", "/calendars/__uids__/user01/calendar/") resource = yield request.locateResource("/calendars/__uids__/user01/calendar/") returnValue(resource)
def test_make_calendar_with_props(self): """ Make calendar with properties (CalDAV-access-09, section 5.3.1.2) """ uri = "/calendars/users/user01/calendar_prop/" path = os.path.join(self.docroot, uri[1:]) if os.path.exists(path): rmdir(path) @inlineCallbacks def do_test(response): response = IResponse(response) if response.code != responsecode.CREATED: self.fail("MKCALENDAR failed: %s" % (response.code,)) resource = (yield request.locateResource(uri)) if not resource.isCalendarCollection(): self.fail("MKCALENDAR made non-calendar collection") for qname, value in ( (davxml.DisplayName.qname(), "Lisa's Events"), (caldavxml.CalendarDescription.qname(), "Calendar restricted to events."), ): stored = yield resource.readProperty(qname, None) stored = str(stored) if stored != value: self.fail("MKCALENDAR failed to set property %s: %s != %s" % (qname, stored, value)) supported_components = yield resource.readProperty(caldavxml.SupportedCalendarComponentSet, None) supported_components = supported_components.children if len(supported_components) != 1: self.fail("MKCALENDAR failed to set property %s: len(%s) != 1" % (caldavxml.SupportedCalendarComponentSet.qname(), supported_components)) if supported_components[0] != caldavxml.CalendarComponent(name="VEVENT"): self.fail("MKCALENDAR failed to set property %s: %s != %s" % (caldavxml.SupportedCalendarComponentSet.qname(), supported_components[0].toxml(), caldavxml.CalendarComponent(name="VEVENT").toxml())) tz = (yield resource.readProperty(caldavxml.CalendarTimeZone, None)) tz = tz.calendar() self.failUnless(tz.resourceType() == "VTIMEZONE") self.failUnless(tuple(tz.subcomponents())[0].propertyValue("TZID") == "US-Eastern") mk = caldavxml.MakeCalendar( davxml.Set( davxml.PropertyContainer( davxml.DisplayName("Lisa's Events"), caldavxml.CalendarDescription("Calendar restricted to events."), # FIXME: lang=en caldavxml.SupportedCalendarComponentSet(caldavxml.CalendarComponent(name="VEVENT")), caldavxml.CalendarTimeZone( """BEGIN:VCALENDAR PRODID:-//Example Corp.//CalDAV Client//EN VERSION:2.0 BEGIN:VTIMEZONE TZID:US-Eastern LAST-MODIFIED:19870101T000000Z BEGIN:STANDARD DTSTART:19671029T020000 RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 TZOFFSETFROM:-0400 TZOFFSETTO:-0500 TZNAME:Eastern Standard Time (US & Canada) END:STANDARD BEGIN:DAYLIGHT DTSTART:19870405T020000 RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4 TZOFFSETFROM:-0500 TZOFFSETTO:-0400 TZNAME:Eastern Daylight Time (US & Canada) END:DAYLIGHT END:VTIMEZONE END:VCALENDAR """ ) ) ) ) request = SimpleStoreRequest(self, "MKCALENDAR", uri, authPrincipal=self.authPrincipal) request.stream = MemoryStream(mk.toxml()) return self.send(request, do_test)