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

source_changes at macosforge.org source_changes at macosforge.org
Fri Dec 3 13:49:47 PST 2010


Revision: 6670
          http://trac.macosforge.org/projects/calendarserver/changeset/6670
Author:   exarkun at twistedmatrix.com
Date:     2010-12-03 13:49:42 -0800 (Fri, 03 Dec 2010)
Log Message:
-----------
Parse some of what the server sends back; use it to construct some of the later queries.

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

Added Paths:
-----------
    CalendarServer/trunk/contrib/performance/loadtest/__init__.py
    CalendarServer/trunk/contrib/performance/loadtest/test_ical.py

Added: CalendarServer/trunk/contrib/performance/loadtest/__init__.py
===================================================================
Modified: CalendarServer/trunk/contrib/performance/loadtest/ical.py
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/ical.py	2010-12-03 18:05:31 UTC (rev 6669)
+++ CalendarServer/trunk/contrib/performance/loadtest/ical.py	2010-12-03 21:49:42 UTC (rev 6670)
@@ -15,6 +15,8 @@
 #
 ##
 
+from xml.etree import ElementTree, ElementPath
+
 from twisted.python.log import err
 from twisted.python.filepath import FilePath
 from twisted.internet.defer import inlineCallbacks
@@ -29,6 +31,37 @@
 
 
 class Principal(object):
+
+    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):
         """
@@ -38,10 +71,36 @@
         @type response: C{str}
         @rtype: C{cls}
         """
-        return 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.
@@ -74,13 +133,14 @@
                     'depth': ['0']}),
             StringProducer(self._STARTUP_PRINCIPAL_PROPFIND))
         d.addCallback(readBody)
+        d.addCallback(Principal.fromPROPFINDResponse)
         return d
 
 
-    def _principalsReport(self):
+    def _principalsReport(self, principalCollectionSet):
         d = self._request(
             'REPORT',
-            self.root + 'principals/',
+            self.root + principalCollectionSet,
             Headers({
                     'content-type': ['text/xml'],
                     'depth': ['0']}),
@@ -89,10 +149,10 @@
         return d
 
 
-    def _calendarHomePropfind(self, user):
+    def _calendarHomePropfind(self, calendarHomeSet):
         d = self._request(
             'PROPFIND',
-            self.root + 'calendars/__uids__/' + user + '/',
+            self.root + calendarHomeSet,
             Headers({
                     'content-type': ['text/xml'],
                     'depth': ['1']}),
@@ -101,10 +161,10 @@
         return d
 
 
-    def _notificationPropfind(self, user):
+    def _notificationPropfind(self, notificationURL):
         d = self._request(
             'PROPFIND',
-            self.root + 'calendars/__uids__/' + user + '/notification/',
+            self.root + notificationURL,
             Headers({
                     'content-type': ['text/xml'],
                     'depth': ['1']}),
@@ -113,10 +173,10 @@
         return d
 
     
-    def _principalReport(self, user):
+    def _principalReport(self, principalURL):
         d = self._request(
             'REPORT',
-            self.root + 'principals/__uids__/' + user + '/',
+            self.root + principalURL,
             Headers({
                     'content-type': ['text/xml'],
                     'depth': ['0']}),
@@ -131,19 +191,27 @@
         Emulate a CalDAV client.
         """
         # Orient ourselves, or something
-        print (yield self._principalPropfind(self.user))
+        principal = yield self._principalPropfind(self.user)
 
         # Do another kind of thing I guess
-        print (yield self._principalsReport())
+        principalCollectionSet = principal.properties[
+            principal.PRINCIPAL_COLLECTION_SET]
+        print (yield self._principalsReport(principalCollectionSet))
 
         # Whatever
-        print (yield self._calendarHomePropfind(self.user))
+        calendarHome = principal.properties[
+            principal.CALENDAR_HOME_SET]
+        print (yield self._calendarHomePropfind(calendarHome))
 
         # Learn stuff I guess
-        print (yield self._notificationPropfind(self.user))
+        notificationURL = principal.properties[
+            principal.NOTIFICATION_URL]
+        print (yield self._notificationPropfind(notificationURL))
 
         # More too
-        print (yield self._principalReport(self.user))
+        principalURL = principal.properties[
+            principal.PRINCIPAL_URL]
+        print (yield self._principalReport(principalURL))
 
 
 def main():

Added: CalendarServer/trunk/contrib/performance/loadtest/test_ical.py
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/test_ical.py	                        (rev 0)
+++ CalendarServer/trunk/contrib/performance/loadtest/test_ical.py	2010-12-03 21:49:42 UTC (rev 6670)
@@ -0,0 +1,139 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+##
+
+from twisted.trial.unittest import TestCase
+
+from ical import Principal
+
+PROPFIND_RESPONSE = """\
+<?xml version='1.0' encoding='UTF-8'?>
+<multistatus xmlns='DAV:'>
+  <response>
+    <href>/principals/__uids__/user01/</href>
+    <propstat>
+      <prop>
+        <principal-collection-set>
+          <href>/principals/</href>
+        </principal-collection-set>
+        <calendar-home-set xmlns='urn:ietf:params:xml:ns:caldav'>
+          <href xmlns='DAV:'>/calendars/__uids__/user01</href>
+        </calendar-home-set>
+        <calendar-user-address-set xmlns='urn:ietf:params:xml:ns:caldav'>
+          <href xmlns='DAV:'>/principals/__uids__/user01/</href>
+          <href xmlns='DAV:'>/principals/users/user01/</href>
+        </calendar-user-address-set>
+        <schedule-inbox-URL xmlns='urn:ietf:params:xml:ns:caldav'>
+          <href xmlns='DAV:'>/calendars/__uids__/user01/inbox/</href>
+        </schedule-inbox-URL>
+        <schedule-outbox-URL xmlns='urn:ietf:params:xml:ns:caldav'>
+          <href xmlns='DAV:'>/calendars/__uids__/user01/outbox/</href>
+        </schedule-outbox-URL>
+        <dropbox-home-URL xmlns='http://calendarserver.org/ns/'>
+          <href xmlns='DAV:'>/calendars/__uids__/user01/dropbox/</href>
+        </dropbox-home-URL>
+        <notification-URL xmlns='http://calendarserver.org/ns/'>
+          <href xmlns='DAV:'>/calendars/__uids__/user01/notification/</href>
+        </notification-URL>
+        <displayname>User 01</displayname>
+        <principal-URL>
+          <href>/principals/__uids__/user01/</href>
+        </principal-URL>
+        <supported-report-set>
+          <supported-report>
+            <report>
+              <acl-principal-prop-set/>
+            </report>
+          </supported-report>
+          <supported-report>
+            <report>
+              <principal-match/>
+            </report>
+          </supported-report>
+          <supported-report>
+            <report>
+              <principal-property-search/>
+            </report>
+          </supported-report>
+          <supported-report>
+            <report>
+              <expand-property/>
+            </report>
+          </supported-report>
+        </supported-report-set>
+      </prop>
+      <status>HTTP/1.1 200 OK</status>
+    </propstat>
+    <propstat>
+      <prop>
+        <xmpp-uri xmlns='http://calendarserver.org/ns/'/>
+      </prop>
+      <status>HTTP/1.1 404 Not Found</status>
+    </propstat>
+  </response>
+</multistatus>
+"""
+
+
+class PrincipalTests(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})
+    """
+    def test_fromPROPFINDResponse(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.
+        """
+        principal = Principal.fromPROPFINDResponse(PROPFIND_RESPONSE)
+        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',
+                        ]),
+             })
+
+
+class SnowLeopardTests(TestCase):
+    """
+    Tests for L{SnowLeopard}.
+    """
+    def test_findCalendars(self):
+        """
+        L{SnowLeopard._findCalendars} accepts a calendar home PROPFIND
+        response body and returns a list of calendar identifiers
+        extracted from it.
+        """
+        client = SnowLeopard(None, None, None, None)
+        client._findCalendars()
+
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20101203/153b093f/attachment-0001.html>


More information about the calendarserver-changes mailing list