[CalendarServer-changes] [8598] CalendarServer/trunk/contrib/performance/loadtest
source_changes at macosforge.org
source_changes at macosforge.org
Fri Jan 27 08:08:24 PST 2012
Revision: 8598
http://trac.macosforge.org/projects/calendarserver/changeset/8598
Author: cdaboo at apple.com
Date: 2012-01-27 08:08:23 -0800 (Fri, 27 Jan 2012)
Log Message:
-----------
When using the new inviter, make sure the client does appropriate attendee auto-complete and freebusy checks.
Modified Paths:
--------------
CalendarServer/trunk/contrib/performance/loadtest/ical.py
CalendarServer/trunk/contrib/performance/loadtest/profiles.py
CalendarServer/trunk/contrib/performance/loadtest/test_ical.py
Modified: CalendarServer/trunk/contrib/performance/loadtest/ical.py
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/ical.py 2012-01-27 03:04:24 UTC (rev 8597)
+++ CalendarServer/trunk/contrib/performance/loadtest/ical.py 2012-01-27 16:08:23 UTC (rev 8598)
@@ -129,6 +129,10 @@
raise NotImplementedError("%r does not implement addEvent" % (self.__class__,))
+ def addInvite(self, href, vcalendar):
+ raise NotImplementedError("%r does not implement addEvent" % (self.__class__,))
+
+
def deleteEvent(self, href):
raise NotImplementedError("%r does not implement deleteEvent" % (self.__class__,))
@@ -798,7 +802,24 @@
d.addCallback(self._localUpdateEvent, href, vcalendar)
return d
+ @inlineCallbacks
+ def addInvite(self, href, vcalendar):
+ """
+ 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(vcalendar.mainComponent().properties('ATTENDEE'))
+ for attendee in attendees:
+ if attendee.value() == self.uuid:
+ continue
+ yield self.checkAttendee(vcalendar, attendee)
+
+ # Now do a normal PUT
+ yield self.addEvent(href, vcalendar)
+
def _localUpdateEvent(self, response, href, vcalendar):
headers = response.headers
etag = headers.getRawHeaders("etag", [None])[0]
@@ -828,6 +849,43 @@
return d
+ @inlineCallbacks
+ def checkAttendee(self, vcalendar, attendee):
+ """
+ This is what the client does when a user does attendee auto-complete whilst creating an
+ event invite. We will run this once for each attendee in a new invite.
+ """
+
+ # Temporarily use some non-test names (some which will return
+ # many results, and others which will return fewer) because the
+ # test account names are all too similar
+ # name = attendee.parameterValue('CN').encode("utf-8")
+ # prefix = name[:4].lower()
+ prefix = random.choice(["chris", "cyru", "dre", "eric", "morg",
+ "well", "wilfr", "witz"])
+
+ email = attendee.parameterValue('EMAIL').encode("utf-8")
+
+ # First try to discover some names to supply to the
+ # auto-completion - we will ignore the response
+ yield self._request(
+ MULTI_STATUS, 'REPORT', self.root + 'principals/',
+ Headers({'content-type': ['text/xml']}),
+ StringProducer(self._USER_LIST_PRINCIPAL_PROPERTY_SEARCH % {
+ 'displayname': prefix,
+ 'email': prefix,
+ 'firstname': prefix,
+ 'lastname': prefix,
+ }))
+
+ # Now learn about the attendee's availability
+ yield self.requestAvailability(
+ vcalendar.mainComponent().getStartDateUTC(),
+ vcalendar.mainComponent().getEndDateUTC(),
+ [u'mailto:' + email],
+ [vcalendar.resourceUID()])
+
+
def requestAvailability(self, start, end, users, mask=set()):
"""
Issue a VFREEBUSY request for I{roughly} the given date range for the
Modified: CalendarServer/trunk/contrib/performance/loadtest/profiles.py
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/profiles.py 2012-01-27 03:04:24 UTC (rev 8597)
+++ CalendarServer/trunk/contrib/performance/loadtest/profiles.py 2012-01-27 16:08:23 UTC (rev 8598)
@@ -374,7 +374,7 @@
return succeed(None)
href = '%s%s.ics' % (calendar.url, uid)
- d = self._client.addEvent(href, vcalendar)
+ d = self._client.addInvite(href, vcalendar)
return self._newOperation("invite", d)
class Accepter(ProfileBase):
Modified: CalendarServer/trunk/contrib/performance/loadtest/test_ical.py
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/test_ical.py 2012-01-27 03:04:24 UTC (rev 8597)
+++ CalendarServer/trunk/contrib/performance/loadtest/test_ical.py 2012-01-27 16:08:23 UTC (rev 8598)
@@ -16,7 +16,7 @@
##
from twisted.python.failure import Failure
-from twisted.internet.defer import Deferred
+from twisted.internet.defer import Deferred, inlineCallbacks, returnValue
from twisted.trial.unittest import TestCase
from twisted.web.http import OK, NO_CONTENT, CREATED, MULTI_STATUS
from twisted.web.http_headers import Headers
@@ -39,29 +39,198 @@
EVENT_UID = 'D94F247D-7433-43AF-B84B-ADD684D023B0'
EVENT = """\
-BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//Apple Inc.//iCal 4.0.3//EN
-CALSCALE:GREGORIAN
-BEGIN:VEVENT
-CREATED:20101018T155454Z
-UID:%(UID)s
-DTEND;TZID=America/New_York:20101028T130000
-ATTENDEE;CN="User 03";CUTYPE=INDIVIDUAL;EMAIL="user03 at example.com";PARTS
- TAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user03 at example.co
- m
-ATTENDEE;CN="User 01";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:user01@
- example.com
-TRANSP:OPAQUE
-SUMMARY:Attended Event
-DTSTART;TZID=America/New_York:20101028T120000
-DTSTAMP:20101018T155513Z
-ORGANIZER;CN="User 01":mailto:user01 at example.com
-SEQUENCE:3
-END:VEVENT
-END:VCALENDAR
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.3//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20101018T155454Z
+UID:%(UID)s
+DTEND;TZID=America/New_York:20101028T130000
+ATTENDEE;CN="User 03";CUTYPE=INDIVIDUAL;EMAIL="user03 at example.com";PARTS
+ TAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user03 at example.co
+ m
+ATTENDEE;CN="User 01";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:user01@
+ example.com
+TRANSP:OPAQUE
+SUMMARY:Attended Event
+DTSTART;TZID=America/New_York:20101028T120000
+DTSTAMP:20101018T155513Z
+ORGANIZER;CN="User 01":mailto:user01 at example.com
+SEQUENCE:3
+END:VEVENT
+END:VCALENDAR
""".replace("\n", "\r\n") % {'UID': EVENT_UID}
+EVENT_INVITE = """\
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.3//EN
+CALSCALE:GREGORIAN
+BEGIN:VTIMEZONE
+TZID:America/New_York
+X-LIC-LOCATION:America/New_York
+BEGIN:STANDARD
+DTSTART:18831118T120358
+RDATE:18831118T120358
+TZNAME:EST
+TZOFFSETFROM:-045602
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19180331T020000
+RRULE:FREQ=YEARLY;UNTIL=19190330T070000Z;BYDAY=-1SU;BYMONTH=3
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19181027T020000
+RRULE:FREQ=YEARLY;UNTIL=19191026T060000Z;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:STANDARD
+DTSTART:19200101T000000
+RDATE:19200101T000000
+RDATE:19420101T000000
+RDATE:19460101T000000
+RDATE:19670101T000000
+TZNAME:EST
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19200328T020000
+RDATE:19200328T020000
+RDATE:19740106T020000
+RDATE:19750223T020000
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19201031T020000
+RDATE:19201031T020000
+RDATE:19450930T020000
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19210424T020000
+RRULE:FREQ=YEARLY;UNTIL=19410427T070000Z;BYDAY=-1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19210925T020000
+RRULE:FREQ=YEARLY;UNTIL=19410928T060000Z;BYDAY=-1SU;BYMONTH=9
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19420209T020000
+RDATE:19420209T020000
+TZNAME:EWT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:19450814T190000
+RDATE:19450814T190000
+TZNAME:EPT
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:19460428T020000
+RRULE:FREQ=YEARLY;UNTIL=19660424T070000Z;BYDAY=-1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19460929T020000
+RRULE:FREQ=YEARLY;UNTIL=19540926T060000Z;BYDAY=-1SU;BYMONTH=9
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:STANDARD
+DTSTART:19551030T020000
+RRULE:FREQ=YEARLY;UNTIL=19661030T060000Z;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19670430T020000
+RRULE:FREQ=YEARLY;UNTIL=19730429T070000Z;BYDAY=-1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19671029T020000
+RRULE:FREQ=YEARLY;UNTIL=20061029T060000Z;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19760425T020000
+RRULE:FREQ=YEARLY;UNTIL=19860427T070000Z;BYDAY=-1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:19870405T020000
+RRULE:FREQ=YEARLY;UNTIL=20060402T070000Z;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20071104T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+CREATED:20101018T155454Z
+UID:%(UID)s
+DTEND;TZID=America/New_York:20101028T130000
+ATTENDEE;CN="User 02";CUTYPE=INDIVIDUAL;EMAIL="user02 at example.com";PARTS
+ TAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user02 at example.co
+ m
+ATTENDEE;CN="User 03";CUTYPE=INDIVIDUAL;EMAIL="user03 at example.com";PARTS
+ TAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user03 at example.co
+ m
+ATTENDEE;CN="User 01";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:urn:uuid:user01
+TRANSP:OPAQUE
+SUMMARY:Attended Event
+DTSTART;TZID=America/New_York:20101028T120000
+DTSTAMP:20101018T155513Z
+ORGANIZER;CN="User 01":urn:uuid:user01
+SEQUENCE:3
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n") % {'UID': EVENT_UID}
+
EVENT_AND_TIMEZONE = """\
BEGIN:VCALENDAR
VERSION:2.0
@@ -1182,6 +1351,96 @@
return d
+ @inlineCallbacks
+ def test_addInvite(self):
+ """
+ L{SnowLeopard.addInvite} PUTs the event passed to it to the
+ server and updates local state to reflect its existence, but
+ it also does attendee auto-complete and free-busy checks before
+ the PUT.
+ """
+
+ calendar = Calendar(caldavxml.calendar, set(('VEVENT',)), u'calendar', u'/mumble/', None)
+ self.client._calendars[calendar.url] = calendar
+
+ vcalendar = Component.fromString(EVENT_INVITE)
+
+ self.client.uuid = u'urn:uuid:user01'
+ self.client.email = u'mailto:user01 at example.com'
+ self.client.outbox = "/calendars/__uids__/user01/outbox/"
+
+ @inlineCallbacks
+ def _testReport(*args):
+ expectedResponseCode, method, url, headers, body = args
+ self.assertEqual(expectedResponseCode, MULTI_STATUS)
+ self.assertEqual(method, 'REPORT')
+ self.assertEqual(url, 'http://127.0.0.1/principals/')
+ self.assertIsInstance(url, str)
+ self.assertEqual(headers.getRawHeaders('content-type'), ['text/xml'])
+
+ consumer = MemoryConsumer()
+ yield body.startProducing(consumer)
+
+ response = MemoryResponse(
+ ('HTTP', '1', '1'), MULTI_STATUS, "MultiStatus", Headers({}),
+ StringProducer(""))
+
+ returnValue(response)
+
+ @inlineCallbacks
+ def _testPost(*args, **kwargs):
+ expectedResponseCode, method, url, headers, body = args
+ self.assertEqual(expectedResponseCode, OK)
+ self.assertEqual(method, 'POST')
+ self.assertEqual(url, 'http://127.0.0.1/calendars/__uids__/user01/outbox/')
+ self.assertIsInstance(url, str)
+ self.assertEqual(headers.getRawHeaders('content-type'), ['text/calendar'])
+
+ consumer = MemoryConsumer()
+ yield body.startProducing(consumer)
+ self.assertNotEqual(consumer.value().find(kwargs["attendee"]), -1)
+
+ response = MemoryResponse(
+ ('HTTP', '1', '1'), OK, "OK", Headers({}),
+ StringProducer(""))
+
+ returnValue(response)
+
+ def _testPost02(*args):
+ return _testPost(*args, attendee="ATTENDEE:mailto:user02 at example.com")
+
+ def _testPost03(*args):
+ return _testPost(*args, attendee="ATTENDEE:mailto:user03 at example.com")
+
+ @inlineCallbacks
+ def _testPut(*args, **kwargs):
+ expectedResponseCode, method, url, headers, body = args
+ self.assertEqual(expectedResponseCode, CREATED)
+ self.assertEqual(method, 'PUT')
+ self.assertEqual(url, 'http://127.0.0.1/mumble/frotz.ics')
+ self.assertIsInstance(url, str)
+ self.assertEqual(headers.getRawHeaders('content-type'), ['text/calendar'])
+
+ consumer = MemoryConsumer()
+ yield body.startProducing(consumer)
+ self.assertEqual(
+ Component.fromString(consumer.value()),
+ Component.fromString(EVENT_INVITE))
+
+ response = MemoryResponse(
+ ('HTTP', '1', '1'), CREATED, "Created", Headers({}),
+ StringProducer(""))
+
+ returnValue(response)
+
+ requests = [_testReport, _testPost02, _testReport, _testPost03, _testPut,]
+
+ def _requestHandler(*args):
+ handler = requests.pop(0)
+ return handler(*args)
+ self.client._request = _requestHandler
+ yield self.client.addInvite('/mumble/frotz.ics', vcalendar)
+
def test_deleteEvent(self):
"""
L{SnowLeopard.deleteEvent} DELETEs the event at the relative
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120127/c8bae697/attachment-0001.html>
More information about the calendarserver-changes
mailing list