[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