def test(response, path, isfile, sum, uri, depth, dst_path): if response.code != responsecode.CREATED: self.fail("Incorrect response code for COPY %s (depth=%r): %s != %s" % (uri, depth, response.code, responsecode.CREATED)) if response.headers.getHeader("location") is None: self.fail("Reponse to COPY %s (depth=%r) with CREATE status is missing location: header." % (uri, depth)) if os.path.isfile(path): if not os.path.isfile(dst_path): self.fail("COPY %s (depth=%r) produced no output file" % (uri, depth)) if not cmp(path, dst_path): self.fail("COPY %s (depth=%r) produced different file" % (uri, depth)) os.remove(dst_path) elif os.path.isdir(path): if not os.path.isdir(dst_path): self.fail("COPY %s (depth=%r) produced no output directory" % (uri, depth)) if depth in ("infinity", None): if dircmp(path, dst_path): self.fail("COPY %s (depth=%r) produced different directory" % (uri, depth)) elif depth == "0": for filename in os.listdir(dst_path): self.fail("COPY %s (depth=%r) shouldn't copy directory contents (eg. %s)" % (uri, depth, filename)) else: raise AssertionError("Unknown depth: %r" % (depth,)) rmdir(dst_path) else: self.fail("Source %s is neither a file nor a directory" % (path,))
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 restore(self): # Get rid of whatever messed up state the test has now so that we'll # get a fresh docroot. This isn't very cool; tests should be doing # less so that they don't need a fresh copy of this state. if hasattr(self, "_docroot"): rmdir(self._docroot) del self._docroot
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_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(response, path, isfile, sum, uri, depth, dst_path): if response.code != responsecode.CREATED: self.fail( "Incorrect response code for COPY %s (depth=%r): %s != %s" % (uri, depth, response.code, responsecode.CREATED)) if response.headers.getHeader("location") is None: self.fail( "Reponse to COPY %s (depth=%r) with CREATE status is missing location: header." % (uri, depth)) if os.path.isfile(path): if not os.path.isfile(dst_path): self.fail("COPY %s (depth=%r) produced no output file" % (uri, depth)) if not cmp(path, dst_path): self.fail("COPY %s (depth=%r) produced different file" % (uri, depth)) os.remove(dst_path) elif os.path.isdir(path): if not os.path.isdir(dst_path): self.fail( "COPY %s (depth=%r) produced no output directory" % (uri, depth)) if depth in ("infinity", None): if dircmp(path, dst_path): self.fail( "COPY %s (depth=%r) produced different directory" % (uri, depth)) elif depth == "0": for filename in os.listdir(dst_path): self.fail( "COPY %s (depth=%r) shouldn't copy directory contents (eg. %s)" % (uri, depth, filename)) else: raise AssertionError("Unknown depth: %r" % (depth, )) rmdir(dst_path) else: self.fail("Source %s is neither a file nor a directory" % (path, ))
def test_addressBookHomeURLs(self): """ DirectoryPrincipalResource.addressBookHomeURLs(), """ # No addressbook home provisioner should result in no addressbook homes. for provisioningResource, _ignore_recordType, recordResource, record in self._allRecords(): if record.enabledForAddressBooks: self.failIf(tuple(recordResource.addressBookHomeURLs())) # Need to create a addressbook home provisioner for each service. addressBookRootResources = {} for directory in self.directoryServices: path = os.path.join(self.docroot, directory.__class__.__name__) if os.path.exists(path): rmdir(path) os.mkdir(path) # Need a data store _newStore = CommonDataStore(path, None, None, True, False) provisioningResource = DirectoryAddressBookHomeProvisioningResource( directory, "/addressbooks/", _newStore ) addressBookRootResources[directory.__class__.__name__] = provisioningResource # AddressBook home provisioners should result in addressBook homes. for provisioningResource, _ignore_recordType, recordResource, record in self._allRecords(): if record.enabledForAddressBooks: homeURLs = tuple(recordResource.addressBookHomeURLs()) self.failUnless(homeURLs) # Turn off enabledForAddressBooks and addressBookHomeURLs should # be empty record.enabledForAddressBooks = False self.failIf(tuple(recordResource.addressBookHomeURLs())) record.enabledForAddressBooks = True addressBookRootURL = addressBookRootResources[record.service.__class__.__name__].url() for homeURL in homeURLs: self.failUnless(homeURL.startswith(addressBookRootURL))
def upgradeCalendarHome(homePath, directory, cuaCache): errorOccurred = False log.debug("Upgrading calendar home: {path}", path=homePath) try: for cal in os.listdir(homePath): calPath = os.path.join(homePath, cal) if not os.path.isdir(calPath): # Skip non-directories; these might have been uploaded by a # random DAV client, they can't be calendar collections. continue if cal == 'notifications': # Delete the old, now obsolete, notifications directory. rmdir(calPath) continue log.debug("Upgrading calendar: {path}", path=calPath) if not (yield upgradeCalendarCollection(calPath, directory, cuaCache)): errorOccurred = True # Change the calendar-free-busy-set xattrs of the inbox to the # __uids__/<guid> form if cal == "inbox": try: for attr, value in xattr.xattr(calPath).iteritems(): if attr == xattrname( "{urn:ietf:params:xml:ns:caldav}calendar-free-busy-set" ): value = yield updateFreeBusySet(value, directory) if value is not None: # Need to write the xattr back to disk xattr.setxattr(calPath, attr, value) except IOError, ioe: if ioe.errno == errno.EOPNOTSUPP: # On non-native xattr systems we cannot do this, # but those systems will typically not be migrating # from pre-v1 pass except: raise
def test_MKCOL(self): """ MKCOL request """ path, uri = self.mkdtemp("collection") rmdir(path) def check_result(response): response = IResponse(response) if response.code != responsecode.CREATED: self.fail("MKCOL response %s != %s" % (response.code, responsecode.CREATED)) if not os.path.isdir(path): self.fail("MKCOL did not create directory %s" % (path,)) request = SimpleRequest(self.site, "MKCOL", uri) return self.send(request, check_result)
def test_MKCOL(self): """ MKCOL request """ path, uri = self.mkdtemp("collection") rmdir(path) def check_result(response): response = IResponse(response) if response.code != responsecode.CREATED: self.fail("MKCOL response %s != %s" % (response.code, responsecode.CREATED)) if not os.path.isdir(path): self.fail("MKCOL did not create directory %s" % (path, )) request = SimpleRequest(self.site, "MKCOL", uri) return self.send(request, check_result)
def upgradeCalendarHome(homePath, directory, cuaCache): errorOccurred = False log.debug("Upgrading calendar home: %s" % (homePath,)) try: for cal in os.listdir(homePath): calPath = os.path.join(homePath, cal) if not os.path.isdir(calPath): # Skip non-directories; these might have been uploaded by a # random DAV client, they can't be calendar collections. continue if cal == 'notifications': # Delete the old, now obsolete, notifications directory. rmdir(calPath) continue log.debug("Upgrading calendar: %s" % (calPath,)) if not upgradeCalendarCollection(calPath, directory, cuaCache): errorOccurred = True # Change the calendar-free-busy-set xattrs of the inbox to the # __uids__/<guid> form if cal == "inbox": try: for attr, value in xattr.xattr(calPath).iteritems(): if attr == xattrname("{urn:ietf:params:xml:ns:caldav}calendar-free-busy-set"): value = updateFreeBusySet(value, directory) if value is not None: # Need to write the xattr back to disk xattr.setxattr(calPath, attr, value) except IOError, ioe: if ioe.errno == errno.EOPNOTSUPP: # On non-native xattr systems we cannot do this, # but those systems will typically not be migrating # from pre-v1 pass except: raise
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_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)
uid, gid = getCalendarServerIDs(config) if not os.path.exists(config.DataRoot): makeDirsUserGroup(config.DataRoot, uid=uid, gid=gid) if os.path.exists(docRoot): # Look for the /principals/ directory on disk oldPrincipals = os.path.join(docRoot, "principals") if os.path.exists(oldPrincipals): # First move the proxy database and rename it doProxyDatabaseMoveUpgrade(config, uid=uid, gid=gid) # Now delete the on disk representation of principals rmdir(oldPrincipals) log.debug( "Removed the old principal directory at '%s'." % (oldPrincipals,) ) calRoot = os.path.join(docRoot, "calendars") if os.path.exists(calRoot): uidHomes = os.path.join(calRoot, "__uids__") # Move calendar homes to new location: log.warn("Moving calendar homes to %s" % (uidHomes,)) if os.path.exists(uidHomes):
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)
def test_calendarHomeURLs(self): """ DirectoryPrincipalResource.calendarHomeURLs(), DirectoryPrincipalResource.scheduleInboxURL(), DirectoryPrincipalResource.scheduleOutboxURL() """ # No calendar home provisioner should result in no calendar homes. for provisioningResource, _ignore_recordType, recordResource, record in self._allRecords(): if record.enabledForCalendaring: self.failIf(tuple(recordResource.calendarHomeURLs())) self.failIf(recordResource.scheduleInboxURL()) self.failIf(recordResource.scheduleOutboxURL()) # Need to create a calendar home provisioner for each service. calendarRootResources = {} for directory in self.directoryServices: path = os.path.join(self.docroot, directory.__class__.__name__) if os.path.exists(path): rmdir(path) os.mkdir(path) # Need a data store _newStore = CommonDataStore(path, None, None, True, False) provisioningResource = DirectoryCalendarHomeProvisioningResource( directory, "/calendars/", _newStore ) calendarRootResources[directory.__class__.__name__] = provisioningResource # Calendar home provisioners should result in calendar homes. for provisioningResource, _ignore_recordType, recordResource, record in self._allRecords(): if record.enabledForCalendaring: homeURLs = tuple(recordResource.calendarHomeURLs()) self.failUnless(homeURLs) # Turn off enabledForCalendaring and calendarHomeURLs should # be empty record.enabledForCalendaring = False self.failIf(tuple(recordResource.calendarHomeURLs())) record.enabledForCalendaring = True calendarRootURL = calendarRootResources[record.service.__class__.__name__].url() inboxURL = recordResource.scheduleInboxURL() outboxURL = recordResource.scheduleOutboxURL() self.failUnless(inboxURL) self.failUnless(outboxURL) for homeURL in homeURLs: self.failUnless(homeURL.startswith(calendarRootURL)) if inboxURL and inboxURL.startswith(homeURL): self.failUnless(len(inboxURL) > len(homeURL)) self.failUnless(inboxURL.endswith("/")) inboxURL = None if outboxURL and outboxURL.startswith(homeURL): self.failUnless(len(outboxURL) > len(homeURL)) self.failUnless(outboxURL.endswith("/")) outboxURL = None self.failIf(inboxURL) self.failIf(outboxURL)