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

source_changes at macosforge.org source_changes at macosforge.org
Wed Aug 15 14:42:52 PDT 2012


Revision: 9711
          http://trac.macosforge.org/projects/calendarserver/changeset/9711
Author:   cdaboo at apple.com
Date:     2012-08-15 14:42:51 -0700 (Wed, 15 Aug 2012)
Log Message:
-----------
Always store calendar data on disk, not in memory to support simulations where users have a lot of calendar data.
Allow each client profile to be given a "title" that is then displayed in the results and used in the serialized data.

Modified Paths:
--------------
    CalendarServer/trunk/contrib/performance/loadtest/config.dist.plist
    CalendarServer/trunk/contrib/performance/loadtest/config.plist
    CalendarServer/trunk/contrib/performance/loadtest/ical.py
    CalendarServer/trunk/contrib/performance/loadtest/profiles.py
    CalendarServer/trunk/contrib/performance/loadtest/test_ical.py
    CalendarServer/trunk/contrib/performance/loadtest/test_profiles.py

Modified: CalendarServer/trunk/contrib/performance/loadtest/config.dist.plist
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/config.dist.plist	2012-08-15 03:38:13 UTC (rev 9710)
+++ CalendarServer/trunk/contrib/performance/loadtest/config.dist.plist	2012-08-15 21:42:51 UTC (rev 9711)
@@ -136,6 +136,10 @@
 				<!-- Arguments to use to initialize the OS_X_10_7 instance. -->
 				<key>params</key>
 				<dict>
+					<!-- Name that appears in logs. -->
+					<key>title</key>
+					<string>10.7</string>
+
 					<!-- OS_X_10_7 can poll the calendar home at some interval. This is 
 						in seconds. -->
 					<key>calendarHomePollInterval</key>

Modified: CalendarServer/trunk/contrib/performance/loadtest/config.plist
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/config.plist	2012-08-15 03:38:13 UTC (rev 9710)
+++ CalendarServer/trunk/contrib/performance/loadtest/config.plist	2012-08-15 21:42:51 UTC (rev 9711)
@@ -123,6 +123,10 @@
 				<!-- Arguments to use to initialize the OS_X_10_7 instance. -->
 				<key>params</key>
 				<dict>
+					<!-- Name that appears in logs. -->
+					<key>title</key>
+					<string>10.7</string>
+	
 					<!-- OS_X_10_7 can poll the calendar home at some interval. This is
 						in seconds. -->
 					<key>calendarHomePollInterval</key>

Modified: CalendarServer/trunk/contrib/performance/loadtest/ical.py
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/ical.py	2012-08-15 03:38:13 UTC (rev 9710)
+++ CalendarServer/trunk/contrib/performance/loadtest/ical.py	2012-08-15 21:42:51 UTC (rev 9711)
@@ -97,51 +97,94 @@
         self.pushkey = pushkey
 
 
+
 def u2str(data):
     return data.encode("utf-8") if type(data) is unicode else data
-    
+
+
+
 class Event(object):
-    def __init__(self, url, etag, vevent=None):
+    def __init__(self, serializeBasePath, url, etag, component=None):
+        self.serializeBasePath = serializeBasePath
         self.url = url
         self.etag = etag
         self.scheduleTag = None
-        self.vevent = vevent
+        if component is not None:
+            self.component = component
+        self.uid = component.resourceUID() if component is not None else None
 
 
     def getUID(self):
         """
-        Return the UID from the vevent, if there is one.
+        Return the UID of the calendar resource.
         """
-        if self.vevent is not None:
-            return self.vevent.resourceUID()
-        return None
+        return self.uid
 
 
+    def serializePath(self):
+        if self.serializeBasePath:
+            calendar = os.path.join(self.serializeBasePath, self.url.split("/")[-2])
+            if not os.path.exists(calendar):
+                os.makedirs(calendar)
+            return os.path.join(calendar, self.url.split("/")[-1])
+        else:
+            return None
+
     def serialize(self):
         """
         Create a dict of the data so we can serialize as JSON.
         """
         
         result = {}
-        for attr in ("url", "etag", "scheduleTag"):
+        for attr in ("url", "etag", "scheduleTag", "uid",):
             result[attr] = getattr(self, attr)
-        result["icalendar"] = str(self.vevent)
         return result
 
+
     @staticmethod
-    def deserialize(data):
+    def deserialize(serializeLocation, data):
         """
         Convert dict (deserialized from JSON) into an L{Event}.
         """
         
-        event = Event(None, None)
-        for attr in ("url", "etag", "scheduleTag"):
+        event = Event(serializeLocation, None, None)
+        for attr in ("url", "etag", "scheduleTag", "uid",):
             setattr(event, attr, u2str(data[attr]))
-        event.vevent = Component.fromString(data["icalendar"])
         return event
 
 
+    @property
+    def component(self):
+        """
+        Data always read from disk - never cached in the object.
+        """
+        path = self.serializePath()
+        return Component.fromString(open(path).read()) if path and os.path.exists(path) else None
 
+
+    @component.setter
+    def component(self, component):
+        """
+        Data always written to disk - never cached on the object.
+        """
+        path = self.serializePath()
+        if path:
+            if component is None:
+                os.remove(path)
+            else:
+                open(path, "w").write(str(component))
+        self.uid = component.resourceUID() if component is not None else None
+
+
+    def removed(self):
+        """
+        Resource no longer exists on the server - remove associated data.
+        """
+        path = self.serializePath()
+        if path and os.path.exists(path):
+            os.remove(path)
+
+
 class Calendar(object):
     def __init__(self, resourceType, componentTypes, name, url, changeToken):
         self.resourceType = resourceType
@@ -168,7 +211,7 @@
     @staticmethod
     def deserialize(data, events):
         """
-        Convert dict (deserialized from JSON) into an L{Event}.
+        Convert dict (deserialized from JSON) into an L{Calendar}.
         """
         
         calendar = Calendar(None, None, None, None, None)
@@ -205,27 +248,28 @@
         Cache the provided event
         """
         self._events[href] = event
-        calendar, uid = href.rsplit('/', 1)
-        self._calendars[calendar + '/'].events[uid] = event
+        calendar, basePath = href.rsplit('/', 1)
+        self._calendars[calendar + '/'].events[basePath] = event
 
 
     def _removeEvent(self, href):
         """
         Remove event from local cache.
         """
+        self._events[href].removed()
         del self._events[href]
-        calendar, uid = href.rsplit('/', 1)
-        del self._calendars[calendar + '/'].events[uid]
+        calendar, basePath = href.rsplit('/', 1)
+        del self._calendars[calendar + '/'].events[basePath]
 
 
-    def addEvent(self, href, vcalendar):
+    def addEvent(self, href, calendar):
         """
         Called when a profile needs to add an event (no scheduling).
         """
         raise NotImplementedError("%r does not implement addEvent" % (self.__class__,))
 
 
-    def addInvite(self, href, vcalendar):
+    def addInvite(self, href, calendar):
         """
         Called when a profile needs to add a new invite. The iCalendar data will already
         contain ATTENDEEs.
@@ -339,6 +383,7 @@
         serializePath,
         record,
         auth,
+        title=None,
         calendarHomePollInterval=None,
         supportPush=True,
         supportAmpPush=True,
@@ -359,6 +404,8 @@
         self.principalPathTemplate = principalPathTemplate
         self.record = record
 
+        self.title = title if title else self._client_type
+
         if calendarHomePollInterval is None:
             calendarHomePollInterval = self.CALENDAR_HOME_POLL_INTERVAL
         self.calendarHomePollInterval = calendarHomePollInterval
@@ -417,7 +464,8 @@
         client specific things, Accept etc.
         """
         headers.setRawHeaders('User-Agent', [self.USER_AGENT])
-        
+
+
     @inlineCallbacks
     def _request(self, expectedResponseCodes, method, url, headers=None, body=None, method_label=None):
         """
@@ -433,7 +481,7 @@
             method=method_label if method_label else method,
             url=url,
             user=self.record.uid,
-            client_type=self._client_type,
+            client_type=self.title,
             client_id=self._client_id,
         )
 
@@ -455,7 +503,7 @@
             body=body,
             code=response.code,
             user=self.record.uid,
-            client_type=self._client_type,
+            client_type=self.title,
             client_id=self._client_id,
             duration=(after - before),
             url=url,
@@ -814,7 +862,7 @@
             # Differentiate a remove vs new/update result
             if result[responseHref].getStatus() / 100 == 2:
                 if responseHref not in self._events:
-                    self._setEvent(responseHref, Event(responseHref, None))
+                    self._setEvent(responseHref, Event(self.serializeLocation(), responseHref, None))
                     
                 event = self._events[responseHref]
                 if event.etag != etag:
@@ -860,7 +908,7 @@
                 continue
 
             if responseHref not in self._events:
-                self._setEvent(responseHref, Event(responseHref, None))
+                self._setEvent(responseHref, Event(self.serializeLocation(), responseHref, None))
                 
             event = self._events[responseHref]
             if event.etag != etag:
@@ -909,7 +957,7 @@
         event.etag = etag
         if scheduleTag is not None:
             event.scheduleTag = scheduleTag
-        event.vevent = Component.fromString(body)
+        event.component = Component.fromString(body)
         self.catalog["eventChanged"].issue(href)
 
                 
@@ -1077,7 +1125,7 @@
             type="operation",
             phase="start",
             user=self.record.uid, 
-            client_type=self._client_type,
+            client_type=self.title,
             client_id=self._client_id,
             label=label,
         )
@@ -1100,7 +1148,7 @@
             phase="end",
             duration=after - before,
             user=self.record.uid,
-            client_type=self._client_type,
+            client_type=self.title,
             client_id=self._client_id,
             label=label,
             success=success,
@@ -1167,7 +1215,7 @@
                 raise MissingCalendarHome
             yield self._checkCalendarsForEvents(calendarHome, firstTime=True)
             returnValue(calendarHome)
-        calendarHome = yield self._newOperation("startup: %s" % (self._client_type,), startup())
+        calendarHome = yield self._newOperation("startup: %s" % (self.title,), startup())
 
         self.started = True
 
@@ -1198,16 +1246,30 @@
         return self._unsubscribePubSub()
 
 
+    def serializeLocation(self):
+        """
+        Return the path to the directory where data for this user is serialized.
+        """
+        if self.serializePath is None or not os.path.isdir(self.serializePath):
+            return None
+        
+        key = "%s-%s" % (self.record.uid, self.title.replace(" ", "_"))
+        path = os.path.join(self.serializePath, key)
+        if not os.path.exists(path):
+            os.mkdir(path)
+        elif not os.path.isdir(path):
+            return None
+        
+        return path
+        
     def serialize(self):
         """
         Write current state to disk.
         """
         
-        if self.serializePath is None or not os.path.isdir(self.serializePath):
+        path = self.serializeLocation()
+        if path is None:
             return
-        
-        key = "%s-%s.json" % (self.record.uid, self._client_type.replace(" ", "_"))
-        path = os.path.join(self.serializePath, key)
 
         # Create dict for all the data we need to store
         data = {
@@ -1217,7 +1279,7 @@
         }
 
         # Write JSON data
-        json.dump(data, open(path, "w"), indent=2)
+        json.dump(data, open(os.path.join(path, "index.json"), "w"), indent=2)
         
 
     def deserialize(self):
@@ -1225,17 +1287,16 @@
         Read state from disk.
         """
         
-        if self.serializePath is None or not os.path.isdir(self.serializePath):
-            return
-        
         self._calendars = {}
         self._events = {}
 
+        path = self.serializeLocation()
+        if path is None:
+            return
+        
         # Parse JSON data for calendars
-        key = "%s-%s.json" % (self.record.uid, self._client_type.replace(" ", "_"))
-        path = os.path.join(self.serializePath, key)
         try:
-            data = json.load(open(path))
+            data = json.load(open(os.path.join(path, "index.json")))
         except IOError:
             return
 
@@ -1243,7 +1304,7 @@
 
         # Extract all the events first, then do the calendars (which reference the events)
         for event in data["events"]:
-            event = Event.deserialize(event)
+            event = Event.deserialize(self.serializeLocation(), event)
             self._events[event.url] = event
         for calendar in data["calendars"]:
             calendar = Calendar.deserialize(calendar, self._events)
@@ -1278,21 +1339,21 @@
     def addEventAttendee(self, href, attendee):
 
         event = self._events[href]
-        vevent = event.vevent
+        component = event.component
 
         # Trigger auto-complete behavior
-        yield self._attendeeAutoComplete(vevent, attendee)
+        yield self._attendeeAutoComplete(component, attendee)
 
         # If the event has no attendees, add ourselves as an attendee.
-        attendees = list(vevent.mainComponent().properties('ATTENDEE'))
+        attendees = list(component.mainComponent().properties('ATTENDEE'))
         if len(attendees) == 0:
             # First add ourselves as a participant and as the
             # organizer.  In the future for this event we should
             # already have those roles.
-            vevent.mainComponent().addProperty(self._makeSelfOrganizer())
-            vevent.mainComponent().addProperty(self._makeSelfAttendee())
+            component.mainComponent().addProperty(self._makeSelfOrganizer())
+            component.mainComponent().addProperty(self._makeSelfAttendee())
         attendees.append(attendee)
-        vevent.mainComponent().addProperty(attendee)
+        component.mainComponent().addProperty(attendee)
 
         label_suffix = "small"
         if len(attendees) > 5:
@@ -1310,7 +1371,7 @@
             Headers({
                     'content-type': ['text/calendar'],
                     'if-match': [event.etag]}),
-            StringProducer(vevent.getTextWithTimezones(includeTimezones=True)),
+            StringProducer(component.getTextWithTimezones(includeTimezones=True)),
             method_label="PUT{organizer-%s}" % (label_suffix,)
         )
 
@@ -1319,7 +1380,7 @@
 
 
     @inlineCallbacks
-    def _attendeeAutoComplete(self, vevent, attendee):
+    def _attendeeAutoComplete(self, component, attendee):
 
         if self._ATTENDEE_LOOKUPS:
             # Temporarily use some non-test names (some which will return
@@ -1352,21 +1413,21 @@
     
             # Now learn about the attendee's availability
             yield self.requestAvailability(
-                vevent.mainComponent().getStartDateUTC(),
-                vevent.mainComponent().getEndDateUTC(),
+                component.mainComponent().getStartDateUTC(),
+                component.mainComponent().getEndDateUTC(),
                 [self.email, u'mailto:' + email],
-                [vevent.resourceUID()]
+                [component.resourceUID()]
             )
 
 
     @inlineCallbacks
     def changeEventAttendee(self, href, oldAttendee, newAttendee):
         event = self._events[href]
-        vevent = event.vevent
+        component = event.component
 
         # Change the event to have the new attendee instead of the old attendee
-        vevent.mainComponent().removeProperty(oldAttendee)
-        vevent.mainComponent().addProperty(newAttendee)
+        component.mainComponent().removeProperty(oldAttendee)
+        component.mainComponent().addProperty(newAttendee)
         okCodes = NO_CONTENT
         headers = Headers({
                 'content-type': ['text/calendar'],
@@ -1375,7 +1436,7 @@
             headers.addRawHeader('if-schedule-tag-match', event.scheduleTag)
             okCodes = (NO_CONTENT, PRECONDITION_FAILED,)
 
-        attendees = list(vevent.mainComponent().properties('ATTENDEE'))
+        attendees = list(component.mainComponent().properties('ATTENDEE'))
         label_suffix = "small"
         if len(attendees) > 5:
             label_suffix = "medium"
@@ -1388,9 +1449,11 @@
             okCodes,
             'PUT',
             self.root + href.encode('utf-8'),
-            headers, StringProducer(vevent.getTextWithTimezones(includeTimezones=True)),
+            headers, StringProducer(component.getTextWithTimezones(includeTimezones=True)),
             method_label="PUT{attendee-%s}" % (label_suffix,),
         )
+
+        # Finally, re-retrieve the event to update the etag
         self._updateEvent(response, href)
 
 
@@ -1413,12 +1476,12 @@
 
 
     @inlineCallbacks
-    def addEvent(self, href, vcalendar, invite=False):
+    def addEvent(self, href, component, invite=False):
         headers = Headers({
                 'content-type': ['text/calendar'],
                 })
 
-        attendees = list(vcalendar.mainComponent().properties('ATTENDEE'))
+        attendees = list(component.mainComponent().properties('ATTENDEE'))
         label_suffix = "small"
         if len(attendees) > 5:
             label_suffix = "medium"
@@ -1432,36 +1495,36 @@
             'PUT',
             self.root + href.encode('utf-8'),
             headers,
-            StringProducer(vcalendar.getTextWithTimezones(includeTimezones=True)),
+            StringProducer(component.getTextWithTimezones(includeTimezones=True)),
             method_label="PUT{organizer-%s}" % (label_suffix,) if invite else "PUT{event}",
         )
-        self._localUpdateEvent(response, href, vcalendar)
+        self._localUpdateEvent(response, href, component)
 
 
     @inlineCallbacks
-    def addInvite(self, href, vevent):
+    def addInvite(self, href, component):
         """
         Add an event that is an invite - i.e., has attendees. We will do attendee lookups and freebusy
         checks on each attendee to simulate what happens when an organizer creates a new invite.
         """
         
         # Do lookup and free busy of each attendee (not self)
-        attendees = list(vevent.mainComponent().properties('ATTENDEE'))
+        attendees = list(component.mainComponent().properties('ATTENDEE'))
         for attendee in attendees:
             if attendee.value() in (self.uuid, self.email):
                 continue
-            yield self._attendeeAutoComplete(vevent, attendee)
+            yield self._attendeeAutoComplete(component, attendee)
         
         # Now do a normal PUT
-        yield self.addEvent(href, vevent, invite=True)
+        yield self.addEvent(href, component, invite=True)
 
 
-    def _localUpdateEvent(self, response, href, vcalendar):
+    def _localUpdateEvent(self, response, href, component):
         headers = response.headers
         etag = headers.getRawHeaders("etag", [None])[0]
         scheduleTag = headers.getRawHeaders("schedule-tag", [None])[0]
 
-        event = Event(href, etag, vcalendar)
+        event = Event(self.serializeLocation(), href, etag, component)
         event.scheduleTag = scheduleTag
         self._setEvent(href, event)
 

Modified: CalendarServer/trunk/contrib/performance/loadtest/profiles.py
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/profiles.py	2012-08-15 03:38:13 UTC (rev 9710)
+++ CalendarServer/trunk/contrib/performance/loadtest/profiles.py	2012-08-15 21:42:51 UTC (rev 9711)
@@ -95,7 +95,7 @@
             type="operation",
             phase="start",
             user=self._client.record.uid,
-            client_type=self._client._client_type,
+            client_type=self._client.title,
             client_id=self._client._client_id,
             label=label,
             lag=lag,
@@ -112,7 +112,7 @@
                 phase="end",
                 duration=after - before,
                 user=self._client.record.uid,
-                client_type=self._client._client_type,
+                client_type=self._client.title,
                 client_id=self._client._client_id,
                 label=label,
                 success=success,
@@ -236,12 +236,12 @@
             while events:
                 uuid = self.random.choice(events)
                 events.remove(uuid)
-                event = calendar.events[uuid].vevent
+                event = calendar.events[uuid].component
                 if event is None:
                     continue
 
-                vevent = event.mainComponent()
-                organizer = vevent.getOrganizerProperty()
+                component = event.mainComponent()
+                organizer = component.getOrganizerProperty()
                 if organizer is not None and not self._isSelfAttendee(organizer):
                     # This event was organized by someone else, don't try to invite someone to it.
                     continue
@@ -249,7 +249,7 @@
                 href = calendar.url + uuid
 
                 # Find out who might attend
-                attendees = tuple(vevent.properties('ATTENDEE'))
+                attendees = tuple(component.properties('ATTENDEE'))
 
                 d = self._addAttendee(event, attendees)
                 d.addCallbacks(
@@ -448,10 +448,10 @@
         if href in self._accepting:
             return
 
-        vevent = self._client._events[href].vevent
+        component = self._client._events[href].component
         # Check to see if this user is in the attendee list in the
         # NEEDS-ACTION PARTSTAT.
-        attendees = tuple(vevent.mainComponent().properties('ATTENDEE'))
+        attendees = tuple(component.mainComponent().properties('ATTENDEE'))
         for attendee in attendees:
             if self._isSelfAttendee(attendee):
                 if attendee.parameterValue('PARTSTAT') == 'NEEDS-ACTION':
@@ -465,8 +465,8 @@
         if href in self._accepting:
             return
 
-        vevent = self._client._events[href].vevent
-        method = vevent.propertyValue('METHOD')
+        component = self._client._events[href].component
+        method = component.propertyValue('METHOD')
         if method == "REPLY":
             # Replies are immediately deleted
             self._accepting.add(href)

Modified: CalendarServer/trunk/contrib/performance/loadtest/test_ical.py
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/test_ical.py	2012-08-15 03:38:13 UTC (rev 9710)
+++ CalendarServer/trunk/contrib/performance/loadtest/test_ical.py	2012-08-15 21:42:51 UTC (rev 9711)
@@ -412,7 +412,7 @@
         When the C{vevent} attribute of an L{Event} instance is set,
         L{Event.getUID} returns the UID value from it.
         """
-        event = Event(u'/foo/bar', u'etag', Component.fromString(EVENT))
+        event = Event(None, u'/foo/bar', u'etag', Component.fromString(EVENT))
         self.assertEquals(event.getUID(), EVENT_UID)
 
 
@@ -421,7 +421,7 @@
         When an L{Event} has a C{vevent} attribute set to C{None},
         L{Event.getUID} returns C{None}.
         """
-        event = Event(u'/bar/baz', u'etag')
+        event = Event(None, u'/bar/baz', u'etag')
         self.assertIdentical(event.getUID(), None)
 
 
@@ -1158,11 +1158,13 @@
         TimezoneCache.create()
         self.record = _DirectoryRecord(
             u"user91", u"user91", u"User 91", u"user91 at example.org")
+        serializePath = self.mktemp()
+        os.mkdir(serializePath)
         self.client = OS_X_10_6(
             None,
             "http://127.0.0.1",
             "/principals/users/%s/",
-            None,
+            serializePath,
             self.record,
             None,
         )
@@ -1282,7 +1284,7 @@
         old = attendees[0]
         new = old.duplicate()
         new.setParameter('CN', 'Some Other Guy')
-        event = Event(u'/some/calendar/1234.ics', None, vevent)
+        event = Event(None, u'/some/calendar/1234.ics', None, vevent)
         self.client._events[event.url] = event
         self.client.changeEventAttendee(event.url, old, new)
 
@@ -1445,7 +1447,7 @@
         requests = self.interceptRequests()
 
         calendar = Calendar(caldavxml.calendar, set(('VEVENT',)), u'calendar', u'/foo/', None)
-        event = Event(calendar.url + u'bar.ics', None)
+        event = Event(None, calendar.url + u'bar.ics', None)
         self.client._calendars[calendar.url] = calendar
         self.client._setEvent(event.url, event)
 
@@ -1474,9 +1476,43 @@
         """
         L{OS_X_10_6.serialize} properly generates a JSON document.
         """
+        clientPath = os.path.join(self.client.serializePath, "user91-OS_X_10.6")
+        self.assertFalse(os.path.exists(clientPath))
+        indexPath = os.path.join(clientPath, "index.json")
+        self.assertFalse(os.path.exists(indexPath))
+
+        cal1 = """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//Apple Inc.//iCal 4.0.3//EN
+BEGIN:VEVENT
+UID:004f8e41-b071-4b30-bb3b-6aada4adcc10
+DTSTART:20120817T113000
+DTEND:20120817T114500
+DTSTAMP:20120815T154420Z
+SEQUENCE:2
+SUMMARY:Simple event
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+        cal2 = """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:REQUEST
+PRODID:-//Apple Inc.//iCal 4.0.3//EN
+BEGIN:VEVENT
+UID:00a79cad-857b-418e-a54a-340b5686d747
+DTSTART:20120817T113000
+DTEND:20120817T114500
+DTSTAMP:20120815T154420Z
+SEQUENCE:2
+SUMMARY:Simple event
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
         events = (
-            Event(u'/home/calendar/1.ics', u'123.123', "BEGIN:VALENDAR\r\nEND:VCALENDAR\r\n"),
-            Event(u'/home/inbox/i1.ics', u'123.123', "BEGIN:VALENDAR\r\nMETHOD:REQUEST\r\nEND:VCALENDAR\r\n"),
+            Event(self.client.serializeLocation(), u'/home/calendar/1.ics', u'123.123', Component.fromString(cal1)),
+            Event(self.client.serializeLocation(), u'/home/inbox/i1.ics', u'123.123', Component.fromString(cal2)),
         )
         self.client._events.update(dict([[event.url, event] for event in events]))
 
@@ -1488,16 +1524,11 @@
         self.client._calendars.update(dict([[calendar.url, calendar] for calendar in calendars]))
         self.client._calendars["/home/calendar/"].events["1.ics"] = events[0]
         self.client._calendars["/home/inbox/"].events["i1.ics"] = events[1]
-    
-        tmp = self.mktemp()
-        os.mkdir(tmp)
-        self.client.serializePath = tmp
-        tmpPath = os.path.join(tmp, "user91-OS_X_10.6.json")
-        self.assertFalse(os.path.exists(tmpPath))
 
         self.client.serialize()
-        self.assertTrue(os.path.exists(tmpPath))
-        self.assertEqual(open(tmpPath).read(), """{
+        self.assertTrue(os.path.exists(clientPath))
+        self.assertTrue(os.path.exists(indexPath))
+        self.assertEqual(open(indexPath).read(), """{
   "calendars": [
     {
       "changeToken": "123", 
@@ -1541,28 +1572,65 @@
       "url": "/home/calendar/1.ics", 
       "scheduleTag": null, 
       "etag": "123.123", 
-      "icalendar": "BEGIN:VALENDAR\\r\\nEND:VCALENDAR\\r\\n"
+      "uid": "004f8e41-b071-4b30-bb3b-6aada4adcc10"
     }, 
     {
       "url": "/home/inbox/i1.ics", 
       "scheduleTag": null, 
       "etag": "123.123", 
-      "icalendar": "BEGIN:VALENDAR\\r\\nMETHOD:REQUEST\\r\\nEND:VCALENDAR\\r\\n"
+      "uid": "00a79cad-857b-418e-a54a-340b5686d747"
     }
   ]
 }""")
 
+        event1Path = os.path.join(clientPath, "calendar", "1.ics")
+        self.assertTrue(os.path.exists(event1Path))
+        self.assertEqual(open(event1Path).read(), cal1)
 
+        event2Path = os.path.join(clientPath, "inbox", "i1.ics")
+        self.assertTrue(os.path.exists(event2Path))
+        self.assertEqual(open(event2Path).read(), cal2)
+
+
     def test_deserialization(self):
         """
         L{OS_X_10_6.deserailize} properly parses a JSON document.
         """
 
-        tmp = self.mktemp()
-        os.mkdir(tmp)
-        self.client.serializePath = tmp
-        tmpPath = os.path.join(tmp, "user91-OS_X_10.6.json")
-        open(tmpPath, "w").write("""{
+        cal1 = """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//Apple Inc.//iCal 4.0.3//EN
+BEGIN:VEVENT
+UID:004f8e41-b071-4b30-bb3b-6aada4adcc10
+DTSTART:20120817T113000
+DTEND:20120817T114500
+DTSTAMP:20120815T154420Z
+SEQUENCE:2
+SUMMARY:Simple event
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+        cal2 = """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:REQUEST
+PRODID:-//Apple Inc.//iCal 4.0.3//EN
+BEGIN:VEVENT
+UID:00a79cad-857b-418e-a54a-340b5686d747
+DTSTART:20120817T113000
+DTEND:20120817T114500
+DTSTAMP:20120815T154420Z
+SEQUENCE:2
+SUMMARY:Simple event
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+        clientPath = os.path.join(self.client.serializePath, "user91-OS_X_10.6")
+        os.mkdir(clientPath)
+        indexPath = os.path.join(clientPath, "index.json")
+        open(indexPath, "w").write("""{
   "calendars": [
     {
       "changeToken": "321", 
@@ -1606,17 +1674,24 @@
       "url": "/home/calendar/2.ics", 
       "scheduleTag": null, 
       "etag": "321.321", 
-      "icalendar": "BEGIN:VCALENDAR\\r\\nVERSION:2.0\\r\\nPRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN\\r\\nBEGIN:VEVENT\\r\\nUID:put-1 at example.com\\r\\nDTSTART:20110427\\r\\nDURATION:P1DT\\r\\nDTSTAMP:20051222T205953Z\\r\\nSUMMARY:event 1\\r\\nEND:VEVENT\\r\\nEND:VCALENDAR\\r\\n"
+      "uid": "004f8e41-b071-4b30-bb3b-6aada4adcc10"
     }, 
     {
       "url": "/home/inbox/i2.ics", 
       "scheduleTag": null, 
       "etag": "987.987", 
-      "icalendar": "BEGIN:VCALENDAR\\r\\nVERSION:2.0\\r\\nMETHOD:REQUEST\\r\\nPRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN\\r\\nBEGIN:VEVENT\\r\\nUID:put-1 at example.com\\r\\nDTSTART:20110427\\r\\nDURATION:P1DT\\r\\nDTSTAMP:20051222T205953Z\\r\\nSUMMARY:event 1\\r\\nEND:VEVENT\\r\\nEND:VCALENDAR\\r\\n"
+      "uid": "00a79cad-857b-418e-a54a-340b5686d747"
     }
   ]
 }""")
 
+        os.mkdir(os.path.join(clientPath, "calendar"))
+        event1Path = os.path.join(clientPath, "calendar", "2.ics")
+        open(event1Path, "w").write(cal1)
+        os.mkdir(os.path.join(clientPath, "inbox"))
+        event1Path = os.path.join(clientPath, "inbox", "i2.ics")
+        open(event1Path, "w").write(cal2)
+
         self.client.deserialize()
 
         self.assertEqual(len(self.client._calendars), 3)
@@ -1632,8 +1707,13 @@
         self.assertTrue("/home/calendar/2.ics" in self.client._events)
         self.assertEqual(self.client._events["/home/calendar/2.ics"].scheduleTag, None)
         self.assertEqual(self.client._events["/home/calendar/2.ics"].etag, "321.321")
-        self.assertEqual(self.client._events["/home/calendar/2.ics"].getUID(), "put-1 at example.com")
+        self.assertEqual(self.client._events["/home/calendar/2.ics"].getUID(), "004f8e41-b071-4b30-bb3b-6aada4adcc10")
+        self.assertEqual(str(self.client._events["/home/calendar/2.ics"].component), cal1)
         self.assertTrue("/home/inbox/i2.ics" in self.client._events)
+        self.assertEqual(self.client._events["/home/inbox/i2.ics"].scheduleTag, None)
+        self.assertEqual(self.client._events["/home/inbox/i2.ics"].etag, "987.987")
+        self.assertEqual(self.client._events["/home/inbox/i2.ics"].getUID(), "00a79cad-857b-418e-a54a-340b5686d747")
+        self.assertEqual(str(self.client._events["/home/inbox/i2.ics"].component), cal2)
 
 
 class UpdateCalendarTests(OS_X_10_6Mixin, TestCase):

Modified: CalendarServer/trunk/contrib/performance/loadtest/test_profiles.py
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/test_profiles.py	2012-08-15 03:38:13 UTC (rev 9710)
+++ CalendarServer/trunk/contrib/performance/loadtest/test_profiles.py	2012-08-15 21:42:51 UTC (rev 9711)
@@ -37,6 +37,8 @@
 from contrib.performance.loadtest.ical import IncorrectResponseCode, Calendar, Event, BaseClient
 from contrib.performance.loadtest.sim import _DirectoryRecord
 
+import os
+
 SIMPLE_EVENT = """\
 BEGIN:VCALENDAR
 VERSION:2.0
@@ -212,7 +214,9 @@
         attendee changes due to a changed schedule tag.
     @ivar _pendingFailures: dict mapping URLs to failure objects
     """
-    def __init__(self, number):
+    def __init__(self, number, serializePath):
+        self.serializePath = serializePath
+        os.mkdir(self.serializePath)
         self._events = {}
         self._calendars = {}
         self._pendingFailures = {}
@@ -232,8 +236,25 @@
         self._pendingFailures[href] = failureObject
 
 
+    def serializeLocation(self):
+        """
+        Return the path to the directory where data for this user is serialized.
+        """
+        if self.serializePath is None or not os.path.isdir(self.serializePath):
+            return None
+        
+        key = "%s-%s" % (self.record.uid, "StubClient")
+        path = os.path.join(self.serializePath, key)
+        if not os.path.exists(path):
+            os.mkdir(path)
+        elif not os.path.isdir(path):
+            return None
+        
+        return path
+
+    
     def addEvent(self, href, vevent):
-        self._events[href] = Event(href, None, vevent)
+        self._events[href] = Event(self.serializePath, href, None, vevent)
         return succeed(None)
 
 
@@ -257,8 +278,9 @@
 
 
     def addEventAttendee(self, href, attendee):
-        vevent = self._events[href].vevent
+        vevent = self._events[href].component
         vevent.mainComponent().addProperty(attendee)
+        self._events[href].component = vevent
 
 
     def changeEventAttendee(self, href, old, new):
@@ -269,9 +291,10 @@
                         ('HTTP', 1, 1), PRECONDITION_FAILED,
                         'Precondition Failed', None, None)))
 
-        vevent = self._events[href].vevent
+        vevent = self._events[href].component
         vevent.mainComponent().removeProperty(old)
         vevent.mainComponent().addProperty(new)
+        self._events[href].component = vevent
         return succeed(None)
 
 
@@ -320,21 +343,24 @@
 
 
     def _simpleAccount(self, userNumber, eventText):
+        client = StubClient(userNumber, self.mktemp())
+
         vevent = Component.fromString(eventText)
         calendar = Calendar(
             caldavxml.calendar, set(('VEVENT',)), u'calendar', u'/cal/', None)
-        event = Event(calendar.url + u'1234.ics', None, vevent)
-        calendar.events = {u'1234.ics': event}
-        client = StubClient(userNumber)
-        client._events.update({event.url: event})
         client._calendars.update({calendar.url: calendar})
 
+        event = Event(client.serializeLocation(), calendar.url + u'1234.ics', None, vevent)
+
+        client._events.update({event.url: event})
+        calendar.events = {u'1234.ics': event}
+
         return vevent, event, calendar, client
 
 
     def test_enabled(self):
         userNumber = 13
-        client = StubClient(userNumber)
+        client = StubClient(userNumber, self.mktemp())
 
         inviter = Inviter(None, self.sim, client, userNumber, **{"enabled":False})
         self.assertEqual(inviter.enabled, False)
@@ -342,6 +368,7 @@
         inviter = Inviter(None, self.sim, client, userNumber, **{"enabled":True})
         self.assertEqual(inviter.enabled, True)
 
+
     def test_doNotAddAttendeeToInbox(self):
         """
         When the only calendar with any events is a schedule inbox, no
@@ -362,7 +389,7 @@
         does nothing.
         """
         userNumber = 13
-        client = StubClient(userNumber)
+        client = StubClient(userNumber, self.mktemp())
         inviter = Inviter(None, self.sim, client, userNumber)
         inviter._invite()
         self.assertEquals(client._events, {})
@@ -378,7 +405,7 @@
         userNumber = 19
         _ignore_vevent, event, calendar, client = self._simpleAccount(
             userNumber, SIMPLE_EVENT)
-        event.vevent = event.etag = event.scheduleTag = None
+        event.component = event.etag = event.scheduleTag = None
         inviter = Inviter(None, self.sim, client, userNumber)
         inviter._invite()
         self.assertEquals(client._events, {event.url: event})
@@ -391,12 +418,12 @@
         attendee to it.
         """
         userNumber = 16
-        vevent, _ignore_event, _ignore_calendar, client = self._simpleAccount(
+        _ignore_vevent, event, _ignore_calendar, client = self._simpleAccount(
             userNumber, SIMPLE_EVENT)
         inviter = Inviter(Clock(), self.sim, client, userNumber)
         inviter.setParameters(inviteeDistanceDistribution=Deterministic(1))
         inviter._invite()
-        attendees = tuple(vevent.mainComponent().properties('ATTENDEE'))
+        attendees = tuple(event.component.mainComponent().properties('ATTENDEE'))
         self.assertEquals(len(attendees), 1)
         for paramname, paramvalue in {
             'CN': 'User %d' % (userNumber + 1,),
@@ -416,7 +443,7 @@
         the attendee list, a different user is added instead.
         """
         selfNumber = 12
-        vevent, _ignore_event, _ignore_calendar, client = self._simpleAccount(
+        _ignore_vevent, event, _ignore_calendar, client = self._simpleAccount(
             selfNumber, SIMPLE_EVENT)
 
         otherNumber = 20
@@ -425,7 +452,7 @@
         inviter = Inviter(Clock(), self.sim, client, selfNumber)
         inviter.setParameters(inviteeDistanceDistribution=SequentialDistribution(values))
         inviter._invite()
-        attendees = tuple(vevent.mainComponent().properties('ATTENDEE'))
+        attendees = tuple(event.component.mainComponent().properties('ATTENDEE'))
         self.assertEquals(len(attendees), 1)
         for paramname, paramvalue in {
             'CN': 'User %d' % (otherNumber,),
@@ -445,10 +472,10 @@
         invitee on the event, a different user is added instead.
         """
         selfNumber = 1
-        vevent, _ignore_event, _ignore_calendar, client = self._simpleAccount(
+        _ignore_vevent, event, _ignore_calendar, client = self._simpleAccount(
             selfNumber, INVITED_EVENT)
 
-        invitee = tuple(vevent.mainComponent().properties('ATTENDEE'))[0]
+        invitee = tuple(event.component.mainComponent().properties('ATTENDEE'))[0]
         inviteeNumber = int(invitee.parameterValue('CN').split()[1])
         anotherNumber = inviteeNumber + 5
         values = [inviteeNumber - selfNumber, anotherNumber - selfNumber]
@@ -456,7 +483,7 @@
         inviter = Inviter(Clock(), self.sim, client, selfNumber)
         inviter.setParameters(inviteeDistanceDistribution=SequentialDistribution(values))
         inviter._invite()
-        attendees = tuple(vevent.mainComponent().properties('ATTENDEE'))
+        attendees = tuple(event.component.mainComponent().properties('ATTENDEE'))
         self.assertEquals(len(attendees), 3)
         for paramname, paramvalue in {
             'CN': 'User %02d' % (anotherNumber,),
@@ -517,12 +544,12 @@
 
 
     def _simpleAccount(self, userNumber, eventText):
+        client = StubClient(userNumber, self.mktemp())
         vevent = Component.fromString(eventText)
         calendar = Calendar(
             caldavxml.calendar, set(('VEVENT',)), u'calendar', u'/cal/', None)
-        event = Event(calendar.url + u'1234.ics', None, vevent)
+        event = Event(client.serializeLocation(), calendar.url + u'1234.ics', None, vevent)
         calendar.events = {u'1234.ics': event}
-        client = StubClient(userNumber)
         client._events.update({event.url: event})
         client._calendars.update({calendar.url: calendar})
 
@@ -531,7 +558,7 @@
 
     def test_enabled(self):
         userNumber = 13
-        client = StubClient(userNumber)
+        client = StubClient(userNumber, self.mktemp())
 
         inviter = RealisticInviter(None, self.sim, client, userNumber, **{"enabled":False})
         self.assertEqual(inviter.enabled, False)
@@ -547,7 +574,7 @@
         calendar = Calendar(
             caldavxml.schedule_inbox, set(), u'inbox', u'/sched/inbox', None)
         userNumber = 13
-        client = StubClient(userNumber)
+        client = StubClient(userNumber, self.mktemp())
         client._calendars.update({calendar.url: calendar})
 
         inviter = RealisticInviter(None, self.sim, client, userNumber, **{"enabled":False})
@@ -562,7 +589,7 @@
         does nothing.
         """
         userNumber = 13
-        client = StubClient(userNumber)
+        client = StubClient(userNumber, self.mktemp())
         inviter = RealisticInviter(None, self.sim, client, userNumber)
         inviter._invite()
         self.assertEquals(client._events, {})
@@ -576,7 +603,9 @@
         calendar = Calendar(
             caldavxml.calendar, set(('VEVENT',)), u'personal stuff', u'/cals/personal', None)
         userNumber = 16
-        client = StubClient(userNumber)
+        serializePath = self.mktemp()
+        os.mkdir(serializePath)
+        client = StubClient(userNumber, self.mktemp())
         client._calendars.update({calendar.url: calendar})
         inviter = RealisticInviter(Clock(), self.sim, client, userNumber)
         inviter.setParameters(
@@ -585,7 +614,7 @@
         )
         inviter._invite()
         self.assertEquals(len(client._events), 1)
-        attendees = tuple(client._events.values()[0].vevent.mainComponent().properties('ATTENDEE'))
+        attendees = tuple(client._events.values()[0].component.mainComponent().properties('ATTENDEE'))
         expected = set(("mailto:user%02d at example.com" %  (userNumber,), "mailto:user%02d at example.com" %  (userNumber + 1,),))
         for attendee in attendees:
             expected.remove(attendee.value())
@@ -601,7 +630,7 @@
         calendar = Calendar(
             caldavxml.calendar, set(('VEVENT',)), u'personal stuff', u'/cals/personal', None)
         selfNumber = 12
-        client = StubClient(selfNumber)
+        client = StubClient(selfNumber, self.mktemp())
         client._calendars.update({calendar.url: calendar})
 
         otherNumber = 20
@@ -614,7 +643,7 @@
         )
         inviter._invite()
         self.assertEquals(len(client._events), 1)
-        attendees = tuple(client._events.values()[0].vevent.mainComponent().properties('ATTENDEE'))
+        attendees = tuple(client._events.values()[0].component.mainComponent().properties('ATTENDEE'))
         expected = set(("mailto:user%02d at example.com" %  (selfNumber,), "mailto:user%02d at example.com" %  (otherNumber,),))
         for attendee in attendees:
             expected.remove(attendee.value())
@@ -630,7 +659,7 @@
         calendar = Calendar(
             caldavxml.calendar, set(('VEVENT',)), u'personal stuff', u'/cals/personal', None)
         selfNumber = 1
-        client = StubClient(selfNumber)
+        client = StubClient(selfNumber, self.mktemp())
         client._calendars.update({calendar.url: calendar})
 
         inviteeNumber = 20
@@ -644,7 +673,7 @@
         )
         inviter._invite()
         self.assertEquals(len(client._events), 1)
-        attendees = tuple(client._events.values()[0].vevent.mainComponent().properties('ATTENDEE'))
+        attendees = tuple(client._events.values()[0].component.mainComponent().properties('ATTENDEE'))
         expected = set((
             "mailto:user%02d at example.com" %  (selfNumber,),
             "mailto:user%02d at example.com" %  (inviteeNumber,),
@@ -664,7 +693,7 @@
         calendar = Calendar(
             caldavxml.calendar, set(('VEVENT',)), u'personal stuff', u'/cals/personal', None)
         userNumber = 1
-        client = StubClient(userNumber)
+        client = StubClient(userNumber, self.mktemp())
         client._calendars.update({calendar.url: calendar})
         inviter = RealisticInviter(Clock(), self.sim, client, userNumber)
         inviter.setParameters(
@@ -687,7 +716,7 @@
 
     def test_enabled(self):
         userNumber = 13
-        client = StubClient(userNumber)
+        client = StubClient(userNumber, self.mktemp())
 
         accepter = Accepter(None, self.sim, client, userNumber, **{"enabled":False})
         self.assertEqual(accepter.enabled, False)
@@ -700,7 +729,7 @@
         If an event on an unknown calendar changes, it is ignored.
         """
         userNumber = 13
-        client = StubClient(userNumber)
+        client = StubClient(userNumber, self.mktemp())
         accepter = Accepter(None, self.sim, client, userNumber)
         accepter.eventChanged('/some/calendar/1234.ics')
 
@@ -714,7 +743,7 @@
         calendarURL = '/some/calendar/'
         calendar = Calendar(
             csxml.dropbox_home, set(), u'notification', calendarURL, None)
-        client = StubClient(userNumber)
+        client = StubClient(userNumber, self.mktemp())
         client._calendars[calendarURL] = calendar
         accepter = Accepter(None, self.sim, client, userNumber)
         accepter.eventChanged(calendarURL + '1234.ics')
@@ -731,9 +760,9 @@
         calendarURL = '/some/calendar/'
         calendar = Calendar(
             caldavxml.calendar, set(('VEVENT',)), u'calendar', calendarURL, None)
-        client = StubClient(userNumber)
+        client = StubClient(userNumber, self.mktemp())
         client._calendars[calendarURL] = calendar
-        event = Event(calendarURL + u'1234.ics', None, vevent)
+        event = Event(client.serializeLocation(), calendarURL + u'1234.ics', None, vevent)
         client._events[event.url] = event
         accepter = Accepter(None, self.sim, client, userNumber)
         accepter.eventChanged(event.url)
@@ -754,9 +783,9 @@
         calendarURL = '/some/calendar/'
         calendar = Calendar(
             caldavxml.calendar, set(('VEVENT',)), u'calendar', calendarURL, None)
-        client = StubClient(userNumber)
+        client = StubClient(userNumber, self.mktemp())
         client._calendars[calendarURL] = calendar
-        event = Event(calendarURL + u'1234.ics', None, vevent)
+        event = Event(client.serializeLocation(), calendarURL + u'1234.ics', None, vevent)
         client._events[event.url] = event
         accepter = Accepter(clock, self.sim, client, userNumber)
         accepter.random = Deterministic()
@@ -777,10 +806,10 @@
         vevent = Component.fromString(INBOX_REPLY)
         inbox = Calendar(
             caldavxml.schedule_inbox, set(), u'the inbox', inboxURL, None)
-        client = StubClient(userNumber)
+        client = StubClient(userNumber, self.mktemp())
         client._calendars[inboxURL] = inbox
 
-        inboxEvent = Event(inboxURL + u'4321.ics', None, vevent)
+        inboxEvent = Event(client.serializeLocation(), inboxURL + u'4321.ics', None, vevent)
         client._setEvent(inboxEvent.url, inboxEvent)
         accepter = Accepter(clock, self.sim, client, userNumber) 
         accepter.eventChanged(inboxEvent.url)
@@ -801,10 +830,10 @@
         vevent = Component.fromString(INBOX_REPLY)
         inbox = Calendar(
             caldavxml.schedule_inbox, set(), u'the inbox', inboxURL, None)
-        client = StubClient(userNumber)
+        client = StubClient(userNumber, self.mktemp())
         client._calendars[inboxURL] = inbox
 
-        inboxEvent = Event(inboxURL + u'4321.ics', None, vevent)
+        inboxEvent = Event(client.serializeLocation(), inboxURL + u'4321.ics', None, vevent)
         client._setEvent(inboxEvent.url, inboxEvent)
         client._failDeleteWithObject(inboxEvent.url, IncorrectResponseCode(
                     NO_CONTENT,
@@ -830,7 +859,7 @@
         vevent = Component.fromString(INVITED_EVENT)
         attendees = tuple(vevent.mainComponent().properties('ATTENDEE'))
         userNumber = int(attendees[1].parameterValue('CN').split(None, 1)[1])
-        client = StubClient(userNumber)
+        client = StubClient(userNumber, self.mktemp())
 
         calendarURL = '/some/calendar/'
         calendar = Calendar(
@@ -842,10 +871,10 @@
             caldavxml.schedule_inbox, set(), u'the inbox', inboxURL, None)
         client._calendars[inboxURL] = inbox
 
-        event = Event(calendarURL + u'1234.ics', None, vevent)
+        event = Event(client.serializeLocation(), calendarURL + u'1234.ics', None, vevent)
         client._setEvent(event.url, event)
 
-        inboxEvent = Event(inboxURL + u'4321.ics', None, vevent)
+        inboxEvent = Event(client.serializeLocation(), inboxURL + u'4321.ics', None, vevent)
         client._setEvent(inboxEvent.url, inboxEvent)
 
         accepter = Accepter(clock, self.sim, client, userNumber)
@@ -853,7 +882,7 @@
         accepter.eventChanged(event.url)
         clock.advance(randomDelay)
 
-        vevent = client._events[event.url].vevent
+        vevent = client._events[event.url].component
         attendees = tuple(vevent.mainComponent().properties('ATTENDEE'))
         self.assertEquals(len(attendees), 2)
         self.assertEquals(
@@ -880,9 +909,9 @@
         calendarURL = '/some/calendar/'
         calendar = Calendar(
             caldavxml.calendar, set(('VEVENT',)), u'calendar', calendarURL, None)
-        client = StubClient(userNumber)
+        client = StubClient(userNumber, self.mktemp())
         client._calendars[calendarURL] = calendar
-        event = Event(calendarURL + u'1234.ics', None, vevent)
+        event = Event(client.serializeLocation(), calendarURL + u'1234.ics', None, vevent)
         client._events[event.url] = event
         accepter = Accepter(clock, self.sim, client, userNumber)
         accepter.setParameters(acceptDelayDistribution=Deterministic(randomDelay))
@@ -890,14 +919,14 @@
         clock.advance(randomDelay)
 
         # Now re-set the event so it has to be accepted again
-        event.vevent = Component.fromString(INVITED_EVENT)
+        event.component = Component.fromString(INVITED_EVENT)
 
         # And now re-deliver it
         accepter.eventChanged(event.url)
         clock.advance(randomDelay)
 
         # And ensure that it was accepted again
-        vevent = client._events[event.url].vevent
+        vevent = client._events[event.url].component
         attendees = tuple(vevent.mainComponent().properties('ATTENDEE'))
         self.assertEquals(len(attendees), 2)
         self.assertEquals(
@@ -915,7 +944,7 @@
         """
         clock = Clock()
         userNumber = 2
-        client = StubClient(userNumber)
+        client = StubClient(userNumber, self.mktemp())
         randomDelay = 3
 
         calendarURL = '/some/calendar/'
@@ -924,7 +953,7 @@
         client._calendars[calendarURL] = calendar
 
         vevent = Component.fromString(INVITED_EVENT)
-        event = Event(calendarURL + u'1234.ics', None, vevent)
+        event = Event(client.serializeLocation(), calendarURL + u'1234.ics', None, vevent)
         client._setEvent(event.url, event)
 
         accepter = Accepter(clock, self.sim, client, userNumber)
@@ -951,7 +980,7 @@
 
     def test_enabled(self):
         userNumber = 13
-        client = StubClient(userNumber)
+        client = StubClient(userNumber, self.mktemp())
 
         eventer = Eventer(None, self.sim, client, None, **{"enabled":False})
         self.assertEqual(eventer.enabled, False)
@@ -966,7 +995,7 @@
         """
         calendar = Calendar(
             caldavxml.schedule_inbox, set(), u'inbox', u'/sched/inbox', None)
-        client = StubClient(21)
+        client = StubClient(21, self.mktemp())
         client._calendars.update({calendar.url: calendar})
 
         eventer = Eventer(None, self.sim, client, None)
@@ -982,7 +1011,7 @@
         """
         calendar = Calendar(
             caldavxml.calendar, set(('VEVENT',)), u'personal stuff', u'/cals/personal', None)
-        client = StubClient(31)
+        client = StubClient(31, self.mktemp())
         client._calendars.update({calendar.url: calendar})
 
         eventer = Eventer(Clock(), self.sim, client, None)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120815/d554a348/attachment-0001.html>


More information about the calendarserver-changes mailing list