[CalendarServer-changes] [6682] CalendarServer/trunk/contrib/performance/loadtest

source_changes at macosforge.org source_changes at macosforge.org
Fri Dec 10 09:34:02 PST 2010


Revision: 6682
          http://trac.macosforge.org/projects/calendarserver/changeset/6682
Author:   exarkun at twistedmatrix.com
Date:     2010-12-10 09:33:58 -0800 (Fri, 10 Dec 2010)
Log Message:
-----------
Switch over from my own parsing to CalDAVClientLibrary; also add a test for learning what calendars and calendar-esque things there are.

Modified Paths:
--------------
    CalendarServer/trunk/contrib/performance/loadtest/ical.py
    CalendarServer/trunk/contrib/performance/loadtest/test_ical.py

Modified: CalendarServer/trunk/contrib/performance/loadtest/ical.py
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/ical.py	2010-12-10 01:04:48 UTC (rev 6681)
+++ CalendarServer/trunk/contrib/performance/loadtest/ical.py	2010-12-10 17:33:58 UTC (rev 6682)
@@ -15,14 +15,23 @@
 #
 ##
 
-from xml.etree import ElementTree, ElementPath
+from operator import getitem
 
+from xml.etree import ElementTree
+ElementTree.QName.__repr__ = lambda self: '<QName %r>' % (self.text,)
+
 from twisted.python.log import err
 from twisted.python.filepath import FilePath
-from twisted.internet.defer import inlineCallbacks
+from twisted.internet.defer import Deferred, inlineCallbacks, returnValue
+from twisted.internet.task import LoopingCall
 from twisted.web.http_headers import Headers
 from twisted.web.client import Agent
 
+from protocol.webdav.propfindparser import PropFindParser
+from protocol.webdav.definitions import davxml
+from protocol.caldav.definitions import caldavxml
+from protocol.caldav.definitions import csxml
+
 from httpclient import StringProducer, readBody
 from httpauth import AuthHandlerAgent
 
@@ -30,82 +39,16 @@
     return FilePath(__file__).sibling(label + '.request').getContent()
 
 
-class Principal(object):
+SUPPORTED_REPORT_SET = '{DAV:}supported-report-set'
 
-    PRINCIPAL_COLLECTION_SET = '{DAV:}principal-collection-set'
-    CALENDAR_HOME_SET = '{urn:ietf:params:xml:ns:caldav}calendar-home-set'
-    SCHEDULE_INBOX_URL = '{urn:ietf:params:xml:ns:caldav}schedule-inbox-URL'
-    SCHEDULE_OUTBOX_URL = '{urn:ietf:params:xml:ns:caldav}schedule-outbox-URL'
-    DROPBOX_HOME_URL = '{http://calendarserver.org/ns/}dropbox-home-URL'
-    NOTIFICATION_URL = '{http://calendarserver.org/ns/}notification-URL'
-    DISPLAY_NAME = '{DAV:}displayname'
-    PRINCIPAL_URL = '{DAV:}principal-URL'
-    
-    _singlePropertyNames = [
-        PRINCIPAL_COLLECTION_SET,
-        CALENDAR_HOME_SET,
-        SCHEDULE_INBOX_URL,
-        SCHEDULE_OUTBOX_URL,
-        DROPBOX_HOME_URL,
-        NOTIFICATION_URL,
-        PRINCIPAL_URL,
-        ]
 
-    CALENDAR_USER_ADDRESS_SET = '{urn:ietf:params:xml:ns:caldav}calendar-user-address-set'
-    SUPPORTED_REPORT_SET = '{DAV:}supported-report-set'
-
-    _multiPropertyNames = [
-        CALENDAR_USER_ADDRESS_SET, SUPPORTED_REPORT_SET]
-
-
-    def __init__(self):
-        self.properties = {}
-
-
-    @classmethod
-    def fromPROPFINDResponse(cls, response):
-        """
-        Construct a principal from the body a response to a
-        I{PROPFIND} request for the principal URL.
-
-        @type response: C{str}
-        @rtype: C{cls}
-        """
-        principal = cls()
-
-        document = ElementTree.fromstring(response)
-        pattern = '{DAV:}response/{DAV:}propstat/{DAV:}prop/'
-
-        name = ElementPath.find(document, pattern + cls.DISPLAY_NAME)
-        if name is not None:
-            principal.properties[cls.DISPLAY_NAME] = name.text
-
-        for prop in cls._singlePropertyNames:
-            href = ElementPath.find(document, pattern + prop + '/{DAV:}href')
-            principal.properties[prop] = href.text
-
-        for prop in cls._multiPropertyNames:
-            hrefs = ElementPath.findall(document, pattern + prop + '/{DAV:}href')
-            principal.properties[prop] = set(href.text for href in hrefs)
-
-        reports = ElementPath.findall(
-            document,
-            pattern + cls.SUPPORTED_REPORT_SET +
-            '/{DAV:}supported-report/{DAV:}report')
-        supported = principal.properties[cls.SUPPORTED_REPORT_SET] = set()
-        for report in reports:
-            for which in report:
-                supported.add(which.tag)
-
-        return principal
-
-
-
 class SnowLeopard(object):
     """
     Implementation of the SnowLeopard iCal network behavior.
     """
 
+    CALENDAR_HOME_POLL_INTERVAL = 15
+
     _STARTUP_PRINCIPAL_PROPFIND = loadRequestBody('sl_startup_principal_propfind')
     _STARTUP_PRINCIPALS_REPORT = loadRequestBody('sl_startup_principals_report')
     _STARTUP_CALENDARHOME_PROPFIND = loadRequestBody('sl_startup_calendarhome_propfind')
@@ -123,21 +66,68 @@
         # XXX Do return code checking here.
         return self.agent.request(method, url, headers, body)
 
+
+    def _parsePROPFINDResponse(self, response):
+        """
+        Construct a principal from the body a response to a
+        I{PROPFIND} request for the principal URL.
+
+        @type response: C{str}
+        @rtype: C{cls}
+        """
+        parser = PropFindParser()
+        parser.parseData(response)
+        return parser.getResults()
+
     
+    _CALENDAR_TYPES = set([
+            caldavxml.calendar,
+            caldavxml.schedule_inbox,
+            caldavxml.schedule_outbox,
+            csxml.notification,
+            csxml.dropbox_home,
+            ])
+    def _extractCalendars(self, response):
+        """
+        Parse 
+        """
+        calendars = []
+        principals = self._parsePROPFINDResponse(response)
+
+        # XXX Here, it would be really great to somehow use
+        # CalDAVClientLibrary.client.principal.CalDAVPrincipal.listCalendars
+        for principal in principals:
+            nodes = principals[principal].getNodeProperties()
+            for nodeType in nodes[davxml.resourcetype].getchildren():
+                if nodeType.tag in self._CALENDAR_TYPES:
+                    calendars.append((nodeType.tag, principals[principal]))
+                    break
+        return sorted(calendars)
+
+
     def _principalPropfind(self, user):
+        """
+        Issue a PROPFIND on the likely principal URL for the given
+        user and return a L{Principal} instance constructed from the
+        response.
+        """
+        principalURL = '/principals/__uids__/' + user + '/'
         d = self._request(
             'PROPFIND',
-            self.root + 'principals/__uids__/' + user + '/',
+            self.root + principalURL[1:],
             Headers({
                     'content-type': ['text/xml'],
                     'depth': ['0']}),
             StringProducer(self._STARTUP_PRINCIPAL_PROPFIND))
         d.addCallback(readBody)
-        d.addCallback(Principal.fromPROPFINDResponse)
+        d.addCallback(self._parsePROPFINDResponse)
+        d.addCallback(getitem, principalURL)
         return d
 
 
     def _principalsReport(self, principalCollectionSet):
+        if principalCollectionSet.startswith('/'):
+            principalCollectionSet = principalCollectionSet[1:]
         d = self._request(
             'REPORT',
             self.root + principalCollectionSet,
@@ -150,6 +140,10 @@
 
 
     def _calendarHomePropfind(self, calendarHomeSet):
+        if calendarHomeSet.startswith('/'):
+            calendarHomeSet = calendarHomeSet[1:]
+        if not calendarHomeSet.endswith('/'):
+            calendarHomeSet = calendarHomeSet + '/'
         d = self._request(
             'PROPFIND',
             self.root + calendarHomeSet,
@@ -158,10 +152,16 @@
                     'depth': ['1']}),
             StringProducer(self._STARTUP_CALENDARHOME_PROPFIND))
         d.addCallback(readBody)
+        d.addCallback(self._parsePROPFINDResponse)
+        def report(result):
+            print result
+        d.addCallback(report)
         return d
 
 
     def _notificationPropfind(self, notificationURL):
+        if notificationURL.startswith('/'):
+            notificationURL = notificationURL[1:]
         d = self._request(
             'PROPFIND',
             self.root + notificationURL,
@@ -170,10 +170,13 @@
                     'depth': ['1']}),
             StringProducer(self._STARTUP_NOTIFICATION_PROPFIND))
         d.addCallback(readBody)
+        d.addCallback(self._extractCalendars)
         return d
 
     
     def _principalReport(self, principalURL):
+        if principalURL.startswith('/'):
+            principalURL = principalURL[1:]
         d = self._request(
             'REPORT',
             self.root + principalURL,
@@ -186,34 +189,48 @@
 
 
     @inlineCallbacks
-    def run(self):
-        """
-        Emulate a CalDAV client.
-        """
+    def startup(self):
         # Orient ourselves, or something
         principal = yield self._principalPropfind(self.user)
+        hrefs = principal.getHrefProperties()
 
         # Do another kind of thing I guess
-        principalCollectionSet = principal.properties[
-            principal.PRINCIPAL_COLLECTION_SET]
-        print (yield self._principalsReport(principalCollectionSet))
+        principalCollection = hrefs[caldavxml.principal_collection_set].toString()
+        print (yield self._principalsReport(principalCollection))
 
         # Whatever
-        calendarHome = principal.properties[
-            principal.CALENDAR_HOME_SET]
+        calendarHome = hrefs[caldavxml.calendar_home_set].toString()
         print (yield self._calendarHomePropfind(calendarHome))
 
         # Learn stuff I guess
-        notificationURL = principal.properties[
-            principal.NOTIFICATION_URL]
+        notificationURL = hrefs[caldavxml.notification_URL].toString()
         print (yield self._notificationPropfind(notificationURL))
 
         # More too
-        principalURL = principal.properties[
-            principal.PRINCIPAL_URL]
+        principalURL = hrefs[davxml.principal_URL].toString()
         print (yield self._principalReport(principalURL))
 
+        returnValue(principal)
 
+
+    @inlineCallbacks
+    def run(self):
+        """
+        Emulate a CalDAV client.
+        """
+        principal = yield self.startup()
+        hrefs = principal.getHrefProperties()
+
+        # Poll Calendar Home (and notifications?) every 15 (or
+        # whatever) minutes
+        pollCalendarHome = LoopingCall(
+            self._calendarHomePropfind, 
+            hrefs[caldavxml.calendar_home_set].toString())
+        pollCalendarHome.start(self.CALENDAR_HOME_POLL_INTERVAL)
+
+        yield Deferred()
+
+
 def main():
     from urllib2 import HTTPDigestAuthHandler
     from twisted.internet import reactor

Modified: CalendarServer/trunk/contrib/performance/loadtest/test_ical.py
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/test_ical.py	2010-12-10 01:04:48 UTC (rev 6681)
+++ CalendarServer/trunk/contrib/performance/loadtest/test_ical.py	2010-12-10 17:33:58 UTC (rev 6682)
@@ -17,9 +17,15 @@
 
 from twisted.trial.unittest import TestCase
 
-from ical import Principal
+from protocol.url import URL
+from protocol.webdav.definitions import davxml
+from protocol.caldav.definitions import caldavxml
+from protocol.caldav.definitions import csxml
 
-PROPFIND_RESPONSE = """\
+from ical import SnowLeopard
+
+
+PRINCIPAL_PROPFIND_RESPONSE = """\
 <?xml version='1.0' encoding='UTF-8'?>
 <multistatus xmlns='DAV:'>
   <response>
@@ -88,52 +94,691 @@
 """
 
 
-class PrincipalTests(TestCase):
+CALENDAR_HOME_PROPFIND_RESPONSE = """\
+<?xml version='1.0' encoding='UTF-8'?>
+<multistatus xmlns='DAV:'>
+  <response>
+    <href>/calendars/__uids__/user01/</href>
+    <propstat>
+      <prop>
+        <xmpp-server xmlns='http://calendarserver.org/ns/'/>
+        <xmpp-uri xmlns='http://calendarserver.org/ns/'/>
+        <displayname>User 01</displayname>
+        <resourcetype>
+          <collection/>
+        </resourcetype>
+        <owner>
+          <href>/principals/__uids__/user01/</href>
+        </owner>
+        <quota-available-bytes>104855434</quota-available-bytes>
+        <quota-used-bytes>2166</quota-used-bytes>
+        <current-user-privilege-set>
+          <privilege>
+            <all/>
+          </privilege>
+          <privilege>
+            <read/>
+          </privilege>
+          <privilege>
+            <read-free-busy xmlns='urn:ietf:params:xml:ns:caldav'/>
+          </privilege>
+          <privilege>
+            <write/>
+          </privilege>
+          <privilege>
+            <write-properties/>
+          </privilege>
+          <privilege>
+            <write-content/>
+          </privilege>
+          <privilege>
+            <bind/>
+          </privilege>
+          <privilege>
+            <unbind/>
+          </privilege>
+          <privilege>
+            <unlock/>
+          </privilege>
+          <privilege>
+            <read-acl/>
+          </privilege>
+          <privilege>
+            <write-acl/>
+          </privilege>
+          <privilege>
+            <read-current-user-privilege-set/>
+          </privilege>
+        </current-user-privilege-set>
+        <push-transports xmlns='http://calendarserver.org/ns/'/>
+        <pushkey xmlns='http://calendarserver.org/ns/'/>
+      </prop>
+      <status>HTTP/1.1 200 OK</status>
+    </propstat>
+    <propstat>
+      <prop>
+        <getctag xmlns='http://calendarserver.org/ns/'/>
+        <calendar-description xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <calendar-color xmlns='http://apple.com/ns/ical/'/>
+        <calendar-order xmlns='http://apple.com/ns/ical/'/>
+        <supported-calendar-component-set xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <schedule-calendar-transp xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <schedule-default-calendar-URL xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <calendar-timezone xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <source xmlns='http://calendarserver.org/ns/'/>
+        <subscribed-strip-alarms xmlns='http://calendarserver.org/ns/'/>
+        <subscribed-strip-attachments xmlns='http://calendarserver.org/ns/'/>
+        <subscribed-strip-todos xmlns='http://calendarserver.org/ns/'/>
+        <refreshrate xmlns='http://apple.com/ns/ical/'/>
+        <publish-url xmlns='http://calendarserver.org/ns/'/>
+      </prop>
+      <status>HTTP/1.1 404 Not Found</status>
+    </propstat>
+  </response>
+  <response>
+    <href>/calendars/__uids__/user01/notification/</href>
+    <propstat>
+      <prop>
+        <displayname>notification</displayname>
+        <resourcetype>
+          <collection/>
+          <notification xmlns='http://calendarserver.org/ns/'/>
+        </resourcetype>
+        <owner>
+          <href>/principals/__uids__/user01/</href>
+        </owner>
+        <quota-available-bytes>104855434</quota-available-bytes>
+        <quota-used-bytes>2166</quota-used-bytes>
+        <current-user-privilege-set>
+          <privilege>
+            <all/>
+          </privilege>
+          <privilege>
+            <read/>
+          </privilege>
+          <privilege>
+            <read-free-busy xmlns='urn:ietf:params:xml:ns:caldav'/>
+          </privilege>
+          <privilege>
+            <write/>
+          </privilege>
+          <privilege>
+            <write-properties/>
+          </privilege>
+          <privilege>
+            <write-content/>
+          </privilege>
+          <privilege>
+            <bind/>
+          </privilege>
+          <privilege>
+            <unbind/>
+          </privilege>
+          <privilege>
+            <unlock/>
+          </privilege>
+          <privilege>
+            <read-acl/>
+          </privilege>
+          <privilege>
+            <write-acl/>
+          </privilege>
+          <privilege>
+            <read-current-user-privilege-set/>
+          </privilege>
+        </current-user-privilege-set>
+      </prop>
+      <status>HTTP/1.1 200 OK</status>
+    </propstat>
+    <propstat>
+      <prop>
+        <xmpp-server xmlns='http://calendarserver.org/ns/'/>
+        <xmpp-uri xmlns='http://calendarserver.org/ns/'/>
+        <getctag xmlns='http://calendarserver.org/ns/'/>
+        <calendar-description xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <calendar-color xmlns='http://apple.com/ns/ical/'/>
+        <calendar-order xmlns='http://apple.com/ns/ical/'/>
+        <supported-calendar-component-set xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <schedule-calendar-transp xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <schedule-default-calendar-URL xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <calendar-timezone xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <source xmlns='http://calendarserver.org/ns/'/>
+        <subscribed-strip-alarms xmlns='http://calendarserver.org/ns/'/>
+        <subscribed-strip-attachments xmlns='http://calendarserver.org/ns/'/>
+        <subscribed-strip-todos xmlns='http://calendarserver.org/ns/'/>
+        <refreshrate xmlns='http://apple.com/ns/ical/'/>
+        <push-transports xmlns='http://calendarserver.org/ns/'/>
+        <pushkey xmlns='http://calendarserver.org/ns/'/>
+        <publish-url xmlns='http://calendarserver.org/ns/'/>
+      </prop>
+      <status>HTTP/1.1 404 Not Found</status>
+    </propstat>
+  </response>
+  <response>
+    <href>/calendars/__uids__/user01/dropbox/</href>
+    <propstat>
+      <prop>
+        <resourcetype>
+          <collection/>
+          <dropbox-home xmlns='http://calendarserver.org/ns/'/>
+        </resourcetype>
+        <owner>
+          <href>/principals/__uids__/user01/</href>
+        </owner>
+        <quota-available-bytes>104855434</quota-available-bytes>
+        <quota-used-bytes>2166</quota-used-bytes>
+        <current-user-privilege-set>
+          <privilege>
+            <all/>
+          </privilege>
+          <privilege>
+            <read/>
+          </privilege>
+          <privilege>
+            <read-free-busy xmlns='urn:ietf:params:xml:ns:caldav'/>
+          </privilege>
+          <privilege>
+            <write/>
+          </privilege>
+          <privilege>
+            <write-properties/>
+          </privilege>
+          <privilege>
+            <write-content/>
+          </privilege>
+          <privilege>
+            <bind/>
+          </privilege>
+          <privilege>
+            <unbind/>
+          </privilege>
+          <privilege>
+            <unlock/>
+          </privilege>
+          <privilege>
+            <read-acl/>
+          </privilege>
+          <privilege>
+            <write-acl/>
+          </privilege>
+          <privilege>
+            <read-current-user-privilege-set/>
+          </privilege>
+        </current-user-privilege-set>
+      </prop>
+      <status>HTTP/1.1 200 OK</status>
+    </propstat>
+    <propstat>
+      <prop>
+        <xmpp-server xmlns='http://calendarserver.org/ns/'/>
+        <xmpp-uri xmlns='http://calendarserver.org/ns/'/>
+        <getctag xmlns='http://calendarserver.org/ns/'/>
+        <displayname/>
+        <calendar-description xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <calendar-color xmlns='http://apple.com/ns/ical/'/>
+        <calendar-order xmlns='http://apple.com/ns/ical/'/>
+        <supported-calendar-component-set xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <schedule-calendar-transp xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <schedule-default-calendar-URL xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <calendar-timezone xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <source xmlns='http://calendarserver.org/ns/'/>
+        <subscribed-strip-alarms xmlns='http://calendarserver.org/ns/'/>
+        <subscribed-strip-attachments xmlns='http://calendarserver.org/ns/'/>
+        <subscribed-strip-todos xmlns='http://calendarserver.org/ns/'/>
+        <refreshrate xmlns='http://apple.com/ns/ical/'/>
+        <push-transports xmlns='http://calendarserver.org/ns/'/>
+        <pushkey xmlns='http://calendarserver.org/ns/'/>
+        <publish-url xmlns='http://calendarserver.org/ns/'/>
+      </prop>
+      <status>HTTP/1.1 404 Not Found</status>
+    </propstat>
+  </response>
+  <response>
+    <href>/calendars/__uids__/user01/calendar/</href>
+    <propstat>
+      <prop>
+        <getctag xmlns='http://calendarserver.org/ns/'>c2696540-4c4c-4a31-adaf-c99630776828#3</getctag>
+        <displayname>calendar</displayname>
+        <calendar-color xmlns='http://apple.com/ns/ical/'>#0252D4FF</calendar-color>
+        <calendar-order xmlns='http://apple.com/ns/ical/'>1</calendar-order>
+        <supported-calendar-component-set xmlns='urn:ietf:params:xml:ns:caldav'>
+          <comp name='VEVENT'/>
+          <comp name='VTODO'/>
+          <comp name='VTIMEZONE'/>
+          <comp name='VFREEBUSY'/>
+        </supported-calendar-component-set>
+        <resourcetype>
+          <collection/>
+          <calendar xmlns='urn:ietf:params:xml:ns:caldav'/>
+        </resourcetype>
+        <owner>
+          <href>/principals/__uids__/user01/</href>
+        </owner>
+        <schedule-calendar-transp xmlns='urn:ietf:params:xml:ns:caldav'>
+          <opaque/>
+        </schedule-calendar-transp>
+        <quota-available-bytes>104855434</quota-available-bytes>
+        <quota-used-bytes>2166</quota-used-bytes>
+        <calendar-timezone xmlns='urn:ietf:params:xml:ns:caldav'><![CDATA[BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.3//EN
+CALSCALE:GREGORIAN
+BEGIN:VTIMEZONE
+TZID:America/New_York
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0500
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
+DTSTART:20070311T020000
+TZNAME:EDT
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:-0400
+RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+DTSTART:20071104T020000
+TZNAME:EST
+TZOFFSETTO:-0500
+END:STANDARD
+END:VTIMEZONE
+END:VCALENDAR
+]]></calendar-timezone>
+        <current-user-privilege-set>
+          <privilege>
+            <all/>
+          </privilege>
+          <privilege>
+            <read/>
+          </privilege>
+          <privilege>
+            <read-free-busy xmlns='urn:ietf:params:xml:ns:caldav'/>
+          </privilege>
+          <privilege>
+            <write/>
+          </privilege>
+          <privilege>
+            <write-properties/>
+          </privilege>
+          <privilege>
+            <write-content/>
+          </privilege>
+          <privilege>
+            <bind/>
+          </privilege>
+          <privilege>
+            <unbind/>
+          </privilege>
+          <privilege>
+            <unlock/>
+          </privilege>
+          <privilege>
+            <read-acl/>
+          </privilege>
+          <privilege>
+            <write-acl/>
+          </privilege>
+          <privilege>
+            <read-current-user-privilege-set/>
+          </privilege>
+        </current-user-privilege-set>
+        <pushkey xmlns='http://calendarserver.org/ns/'/>
+      </prop>
+      <status>HTTP/1.1 200 OK</status>
+    </propstat>
+    <propstat>
+      <prop>
+        <xmpp-server xmlns='http://calendarserver.org/ns/'/>
+        <xmpp-uri xmlns='http://calendarserver.org/ns/'/>
+        <calendar-description xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <schedule-default-calendar-URL xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <source xmlns='http://calendarserver.org/ns/'/>
+        <subscribed-strip-alarms xmlns='http://calendarserver.org/ns/'/>
+        <subscribed-strip-attachments xmlns='http://calendarserver.org/ns/'/>
+        <subscribed-strip-todos xmlns='http://calendarserver.org/ns/'/>
+        <refreshrate xmlns='http://apple.com/ns/ical/'/>
+        <push-transports xmlns='http://calendarserver.org/ns/'/>
+        <publish-url xmlns='http://calendarserver.org/ns/'/>
+      </prop>
+      <status>HTTP/1.1 404 Not Found</status>
+    </propstat>
+  </response>
+  <response>
+    <href>/calendars/__uids__/user01/outbox/</href>
+    <propstat>
+      <prop>
+        <supported-calendar-component-set xmlns='urn:ietf:params:xml:ns:caldav'>
+          <comp name='VEVENT'/>
+          <comp name='VTODO'/>
+          <comp name='VTIMEZONE'/>
+          <comp name='VFREEBUSY'/>
+        </supported-calendar-component-set>
+        <resourcetype>
+          <collection/>
+          <schedule-outbox xmlns='urn:ietf:params:xml:ns:caldav'/>
+        </resourcetype>
+        <owner>
+          <href>/principals/__uids__/user01/</href>
+        </owner>
+        <quota-available-bytes>104855434</quota-available-bytes>
+        <quota-used-bytes>2166</quota-used-bytes>
+        <current-user-privilege-set>
+          <privilege>
+            <all/>
+          </privilege>
+          <privilege>
+            <read/>
+          </privilege>
+          <privilege>
+            <write/>
+          </privilege>
+          <privilege>
+            <write-properties/>
+          </privilege>
+          <privilege>
+            <write-content/>
+          </privilege>
+          <privilege>
+            <bind/>
+          </privilege>
+          <privilege>
+            <unbind/>
+          </privilege>
+          <privilege>
+            <unlock/>
+          </privilege>
+          <privilege>
+            <read-acl/>
+          </privilege>
+          <privilege>
+            <write-acl/>
+          </privilege>
+          <privilege>
+            <read-current-user-privilege-set/>
+          </privilege>
+          <privilege>
+            <schedule-send xmlns='urn:ietf:params:xml:ns:caldav'/>
+          </privilege>
+          <privilege>
+            <schedule xmlns='urn:ietf:params:xml:ns:caldav'/>
+          </privilege>
+          <privilege>
+            <read-free-busy xmlns='urn:ietf:params:xml:ns:caldav'/>
+          </privilege>
+        </current-user-privilege-set>
+      </prop>
+      <status>HTTP/1.1 200 OK</status>
+    </propstat>
+    <propstat>
+      <prop>
+        <xmpp-server xmlns='http://calendarserver.org/ns/'/>
+        <xmpp-uri xmlns='http://calendarserver.org/ns/'/>
+        <getctag xmlns='http://calendarserver.org/ns/'/>
+        <displayname/>
+        <calendar-description xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <calendar-color xmlns='http://apple.com/ns/ical/'/>
+        <calendar-order xmlns='http://apple.com/ns/ical/'/>
+        <calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <schedule-calendar-transp xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <schedule-default-calendar-URL xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <calendar-timezone xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <source xmlns='http://calendarserver.org/ns/'/>
+        <subscribed-strip-alarms xmlns='http://calendarserver.org/ns/'/>
+        <subscribed-strip-attachments xmlns='http://calendarserver.org/ns/'/>
+        <subscribed-strip-todos xmlns='http://calendarserver.org/ns/'/>
+        <refreshrate xmlns='http://apple.com/ns/ical/'/>
+        <push-transports xmlns='http://calendarserver.org/ns/'/>
+        <pushkey xmlns='http://calendarserver.org/ns/'/>
+        <publish-url xmlns='http://calendarserver.org/ns/'/>
+      </prop>
+      <status>HTTP/1.1 404 Not Found</status>
+    </propstat>
+  </response>
+  <response>
+    <href>/calendars/__uids__/user01/freebusy</href>
+    <propstat>
+      <prop>
+        <resourcetype>
+          <free-busy-url xmlns='http://calendarserver.org/ns/'/>
+        </resourcetype>
+        <owner>
+          <href>/principals/__uids__/user01/</href>
+        </owner>
+        <quota-available-bytes>104855434</quota-available-bytes>
+        <quota-used-bytes>2166</quota-used-bytes>
+        <current-user-privilege-set>
+          <privilege>
+            <read/>
+          </privilege>
+          <privilege>
+            <schedule-deliver xmlns='urn:ietf:params:xml:ns:caldav'/>
+          </privilege>
+          <privilege>
+            <schedule xmlns='urn:ietf:params:xml:ns:caldav'/>
+          </privilege>
+          <privilege>
+            <all/>
+          </privilege>
+          <privilege>
+            <write/>
+          </privilege>
+          <privilege>
+            <write-properties/>
+          </privilege>
+          <privilege>
+            <write-content/>
+          </privilege>
+          <privilege>
+            <bind/>
+          </privilege>
+          <privilege>
+            <unbind/>
+          </privilege>
+          <privilege>
+            <unlock/>
+          </privilege>
+          <privilege>
+            <read-acl/>
+          </privilege>
+          <privilege>
+            <write-acl/>
+          </privilege>
+          <privilege>
+            <read-current-user-privilege-set/>
+          </privilege>
+          <privilege>
+            <read-free-busy xmlns='urn:ietf:params:xml:ns:caldav'/>
+          </privilege>
+        </current-user-privilege-set>
+      </prop>
+      <status>HTTP/1.1 200 OK</status>
+    </propstat>
+    <propstat>
+      <prop>
+        <xmpp-server xmlns='http://calendarserver.org/ns/'/>
+        <xmpp-uri xmlns='http://calendarserver.org/ns/'/>
+        <getctag xmlns='http://calendarserver.org/ns/'/>
+        <displayname/>
+        <calendar-description xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <calendar-color xmlns='http://apple.com/ns/ical/'/>
+        <calendar-order xmlns='http://apple.com/ns/ical/'/>
+        <supported-calendar-component-set xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <schedule-calendar-transp xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <schedule-default-calendar-URL xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <calendar-timezone xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <source xmlns='http://calendarserver.org/ns/'/>
+        <subscribed-strip-alarms xmlns='http://calendarserver.org/ns/'/>
+        <subscribed-strip-attachments xmlns='http://calendarserver.org/ns/'/>
+        <subscribed-strip-todos xmlns='http://calendarserver.org/ns/'/>
+        <refreshrate xmlns='http://apple.com/ns/ical/'/>
+        <push-transports xmlns='http://calendarserver.org/ns/'/>
+        <pushkey xmlns='http://calendarserver.org/ns/'/>
+        <publish-url xmlns='http://calendarserver.org/ns/'/>
+      </prop>
+      <status>HTTP/1.1 404 Not Found</status>
+    </propstat>
+  </response>
+  <response>
+    <href>/calendars/__uids__/user01/inbox/</href>
+    <propstat>
+      <prop>
+        <getctag xmlns='http://calendarserver.org/ns/'>a483dab3-1391-445b-b1c3-5ae9dfc81c2f#0</getctag>
+        <displayname>inbox</displayname>
+        <supported-calendar-component-set xmlns='urn:ietf:params:xml:ns:caldav'>
+          <comp name='VEVENT'/>
+          <comp name='VTODO'/>
+          <comp name='VTIMEZONE'/>
+          <comp name='VFREEBUSY'/>
+        </supported-calendar-component-set>
+        <resourcetype>
+          <collection/>
+          <schedule-inbox xmlns='urn:ietf:params:xml:ns:caldav'/>
+        </resourcetype>
+        <owner>
+          <href>/principals/__uids__/user01/</href>
+        </owner>
+        <calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'>
+          <href xmlns='DAV:'>/calendars/__uids__/user01/calendar</href>
+        </calendar-free-busy-set>
+        <schedule-default-calendar-URL xmlns='urn:ietf:params:xml:ns:caldav'>
+          <href xmlns='DAV:'>/calendars/__uids__/user01/calendar</href>
+        </schedule-default-calendar-URL>
+        <quota-available-bytes>104855434</quota-available-bytes>
+        <quota-used-bytes>2166</quota-used-bytes>
+        <current-user-privilege-set>
+          <privilege>
+            <schedule-deliver xmlns='urn:ietf:params:xml:ns:caldav'/>
+          </privilege>
+          <privilege>
+            <schedule xmlns='urn:ietf:params:xml:ns:caldav'/>
+          </privilege>
+          <privilege>
+            <all/>
+          </privilege>
+          <privilege>
+            <read/>
+          </privilege>
+          <privilege>
+            <write/>
+          </privilege>
+          <privilege>
+            <write-properties/>
+          </privilege>
+          <privilege>
+            <write-content/>
+          </privilege>
+          <privilege>
+            <bind/>
+          </privilege>
+          <privilege>
+            <unbind/>
+          </privilege>
+          <privilege>
+            <unlock/>
+          </privilege>
+          <privilege>
+            <read-acl/>
+          </privilege>
+          <privilege>
+            <write-acl/>
+          </privilege>
+          <privilege>
+            <read-current-user-privilege-set/>
+          </privilege>
+          <privilege>
+            <read-free-busy xmlns='urn:ietf:params:xml:ns:caldav'/>
+          </privilege>
+        </current-user-privilege-set>
+      </prop>
+      <status>HTTP/1.1 200 OK</status>
+    </propstat>
+    <propstat>
+      <prop>
+        <xmpp-server xmlns='http://calendarserver.org/ns/'/>
+        <xmpp-uri xmlns='http://calendarserver.org/ns/'/>
+        <calendar-description xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <calendar-color xmlns='http://apple.com/ns/ical/'/>
+        <calendar-order xmlns='http://apple.com/ns/ical/'/>
+        <schedule-calendar-transp xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <calendar-timezone xmlns='urn:ietf:params:xml:ns:caldav'/>
+        <source xmlns='http://calendarserver.org/ns/'/>
+        <subscribed-strip-alarms xmlns='http://calendarserver.org/ns/'/>
+        <subscribed-strip-attachments xmlns='http://calendarserver.org/ns/'/>
+        <subscribed-strip-todos xmlns='http://calendarserver.org/ns/'/>
+        <refreshrate xmlns='http://apple.com/ns/ical/'/>
+        <push-transports xmlns='http://calendarserver.org/ns/'/>
+        <pushkey xmlns='http://calendarserver.org/ns/'/>
+        <publish-url xmlns='http://calendarserver.org/ns/'/>
+      </prop>
+      <status>HTTP/1.1 404 Not Found</status>
+    </propstat>
+  </response>
+</multistatus>
+"""
+
+
+
+
+class SnowLeopardTests(TestCase):
     """
-    Tests for L{Principal}, a class for representing "a distinct human
-    or computational actor that initiates access to network
-    resources." (U{http://tools.ietf.org/html/rfc4918})
+    Tests for L{SnowLeopard}.
     """
-    def test_fromPROPFINDResponse(self):
+    def setUp(self):
+        self.client = SnowLeopard(None, "127.0.0.1", 80, None, None)
+
+
+    def test_parsePrincipalPROPFINDResponse(self):
         """
-        L{Principal.fromPROPFINDResponse} accepts an XML document like
-        the one returned from a I{PROPFIND /principals/__uids__/<uid>}
-        and extracts all of the properties from it.
+        L{Principal._parsePROPFINDResponse} accepts an XML document
+        like the one in the response to a I{PROPFIND} request for
+        I{/principals/__uids__/<uid>/} and returns a C{PropFindResult}
+        representing the data from it.
         """
-        principal = Principal.fromPROPFINDResponse(PROPFIND_RESPONSE)
+        principals = self.client._parsePROPFINDResponse(PRINCIPAL_PROPFIND_RESPONSE)
+        principal = principals['/principals/__uids__/user01/']
         self.assertEquals(
-            principal.properties,
-            {Principal.PRINCIPAL_COLLECTION_SET: '/principals/',
-             Principal.CALENDAR_HOME_SET: '/calendars/__uids__/user01',
-             Principal.CALENDAR_USER_ADDRESS_SET: set([
-                    '/principals/__uids__/user01/',
-                    '/principals/users/user01/',
-                    ]),
-             Principal.SCHEDULE_INBOX_URL: '/calendars/__uids__/user01/inbox/',
-             Principal.SCHEDULE_OUTBOX_URL: '/calendars/__uids__/user01/outbox/',
-             Principal.DROPBOX_HOME_URL: '/calendars/__uids__/user01/dropbox/',
-             Principal.NOTIFICATION_URL: '/calendars/__uids__/user01/notification/',
-             Principal.DISPLAY_NAME: 'User 01',
-             Principal.PRINCIPAL_URL: '/principals/__uids__/user01/',
-             Principal.SUPPORTED_REPORT_SET: set([
-                        '{DAV:}acl-principal-prop-set',
-                        '{DAV:}principal-match',
-                        '{DAV:}principal-property-search',
-                        '{DAV:}expand-property',
-                        ]),
+            principal.getHrefProperties(),
+            {davxml.principal_collection_set: URL(path='/principals/'),
+             caldavxml.calendar_home_set: URL(path='/calendars/__uids__/user01'),
+             caldavxml.calendar_user_address_set: (
+                    URL(path='/principals/__uids__/user01/'),
+                    URL(path='/principals/users/user01/'),
+                    ),
+             caldavxml.schedule_inbox_URL: URL(path='/calendars/__uids__/user01/inbox/'),
+             caldavxml.schedule_outbox_URL: URL(path='/calendars/__uids__/user01/outbox/'),
+             csxml.dropbox_home_URL: URL(path='/calendars/__uids__/user01/dropbox/'),
+             csxml.notification_URL: URL(path='/calendars/__uids__/user01/notification/'),
+             davxml.principal_URL: URL(path='/principals/__uids__/user01/'),
              })
+        self.assertEquals(
+            principal.getTextProperties(),
+            {davxml.displayname: 'User 01'})
 
+#         self.assertEquals(
+#             principal.getSomething(),
+#             {SUPPORTED_REPORT_SET: (
+#                     '{DAV:}acl-principal-prop-set',
+#                     '{DAV:}principal-match',
+#                     '{DAV:}principal-property-search',
+#                     '{DAV:}expand-property',
+#                     )})
 
-class SnowLeopardTests(TestCase):
-    """
-    Tests for L{SnowLeopard}.
-    """
-    def test_findCalendars(self):
+
+    def test_extractCalendars(self):
         """
-        L{SnowLeopard._findCalendars} accepts a calendar home PROPFIND
-        response body and returns a list of calendar identifiers
-        extracted from it.
+        L{SnowLeopard._extractCalendars} accepts a calendar home
+        PROPFIND response body and returns a list of calendar objects
+        constructed from the data extracted from the response.
         """
-        client = SnowLeopard(None, None, None, None)
-        client._findCalendars()
-
+        calendars = self.client._extractCalendars(CALENDAR_HOME_PROPFIND_RESPONSE)
+        resourceTypes = [resourceType for (resourceType, element) in calendars]
+        self.assertEquals(
+            resourceTypes,
+            sorted([csxml.dropbox_home,
+                    csxml.notification,
+                    caldavxml.calendar,
+                    caldavxml.schedule_inbox,
+                    caldavxml.schedule_outbox]))
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20101210/41e69988/attachment-0001.html>


More information about the calendarserver-changes mailing list