[CalendarServer-changes] [9342] CalendarServer/trunk/twistedcaldav
source_changes at macosforge.org
source_changes at macosforge.org
Thu Jun 7 18:11:47 PDT 2012
Revision: 9342
http://trac.macosforge.org/projects/calendarserver/changeset/9342
Author: cdaboo at apple.com
Date: 2012-06-07 18:11:47 -0700 (Thu, 07 Jun 2012)
Log Message:
-----------
Fixes to improve performance by doing less work during per user data filtering.
Modified Paths:
--------------
CalendarServer/trunk/twistedcaldav/datafilters/peruserdata.py
CalendarServer/trunk/twistedcaldav/datafilters/test/test_peruserdata.py
CalendarServer/trunk/twistedcaldav/ical.py
CalendarServer/trunk/twistedcaldav/test/test_icalendar.py
Modified: CalendarServer/trunk/twistedcaldav/datafilters/peruserdata.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/datafilters/peruserdata.py 2012-06-08 01:10:12 UTC (rev 9341)
+++ CalendarServer/trunk/twistedcaldav/datafilters/peruserdata.py 2012-06-08 01:11:47 UTC (rev 9342)
@@ -210,6 +210,14 @@
ical.addProperty(property)
def _splitPerUserData(self, ical):
+ """
+ Split the per-user data out of the "normal" iCalendar components into separate per-user
+ components. Along the way keep the iCalendar representation in a "minimal" state by eliminating
+ any components that are the same as the master derived component.
+
+ @param ical: calendar data to process
+ @type ical: L{Component}
+ """
def init_peruser_component():
peruser = Component(PerUserDataFilter.PERUSER_COMPONENT)
@@ -229,8 +237,6 @@
def init_perinstance_component():
peruser = Component(PerUserDataFilter.PERINSTANCE_COMPONENT)
rid = component.getRecurrenceIDUTC()
- if rid:
- peruser.addProperty(Property("RECURRENCE-ID", rid))
perinstance_components[rid] = peruser
return peruser
@@ -253,15 +259,13 @@
if self.uid:
# Add unique per-instance components into the per-user component
master_perinstance = perinstance_components.get(None)
- master_perinstance_txt = str(master_perinstance)
if master_perinstance:
peruser_component.addComponent(master_perinstance)
for rid, perinstance in perinstance_components.iteritems():
if rid is None:
continue
- perinstance_txt = str(perinstance)
- perinstance_txt = "".join([line for line in perinstance_txt.splitlines(True) if not line.startswith("RECURRENCE-ID:")])
- if master_perinstance is None or perinstance_txt != master_perinstance_txt:
+ if master_perinstance is None or perinstance != master_perinstance:
+ perinstance.addProperty(Property("RECURRENCE-ID", rid))
peruser_component.addComponent(perinstance)
self._compactInstances(ical)
@@ -280,16 +284,17 @@
if master is None:
return
+ masterDerived = ical.masterDerived()
+
for subcomponent in tuple(ical.subcomponents()):
if subcomponent.name() == "VTIMEZONE" or subcomponent.name().startswith("X-"):
continue
rid = subcomponent.getRecurrenceIDUTC()
if rid is None:
continue
- derived = ical.deriveInstance(rid)
- if derived:
- if str(derived) == str(subcomponent):
- ical.removeComponent(subcomponent)
+ derived = ical.deriveInstance(rid, newcomp=masterDerived)
+ if derived and derived == subcomponent:
+ ical.removeComponent(subcomponent)
def _mergeRepresentations(self, icalnew, icalold):
Modified: CalendarServer/trunk/twistedcaldav/datafilters/test/test_peruserdata.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/datafilters/test/test_peruserdata.py 2012-06-08 01:10:12 UTC (rev 9341)
+++ CalendarServer/trunk/twistedcaldav/datafilters/test/test_peruserdata.py 2012-06-08 01:11:47 UTC (rev 9342)
@@ -5974,3 +5974,431 @@
for newitem in (newdata, Component.fromString(newdata),):
self.assertEqual(str(PerUserDataFilter("user01").merge(newitem, olditem)), result01)
+
+class PerUserDataMergeTestCompact (twistedcaldav.test.util.TestCase):
+
+ def test_merge_vevent_compact(self):
+
+ newdata = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T110000Z
+DTEND:20080601T120000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+DTSTAMP:20080601T120000Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY;COUNT=5
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-1mod
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T110000Z
+DTSTART:20080602T110000Z
+DTEND:20080602T120000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+DTSTAMP:20080601T120000Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-1mod
+TRIGGER;RELATED=START:-PT5M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+ result = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T110000Z
+DTEND:20080601T120000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+DTSTAMP:20080601T120000Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY;COUNT=5
+END:VEVENT
+BEGIN:X-CALENDARSERVER-PERUSER
+UID:12345-67890
+X-CALENDARSERVER-PERUSER-UID:user01
+BEGIN:X-CALENDARSERVER-PERINSTANCE
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-1mod
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:X-CALENDARSERVER-PERINSTANCE
+BEGIN:X-CALENDARSERVER-PERINSTANCE
+RECURRENCE-ID:20080602T110000Z
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-1mod
+TRIGGER;RELATED=START:-PT5M
+END:VALARM
+END:X-CALENDARSERVER-PERINSTANCE
+END:X-CALENDARSERVER-PERUSER
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ filtered = PerUserDataFilter("user01").merge(newdata, None)
+ self.assertEqual(str(filtered), result)
+ unfiltered = PerUserDataFilter("user01").filter(filtered)
+ self.assertEqual(str(unfiltered), newdata)
+
+
+ def test_merge_vevent_all_day_compact(self):
+
+ newdata = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DTEND;VALUE=DATE:20080602
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+DTSTAMP:20080601T120000Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY;COUNT=5
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-1mod
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID;VALUE=DATE:20080602
+DTSTART;VALUE=DATE:20080602
+DTEND;VALUE=DATE:20080603
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+DTSTAMP:20080601T120000Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-1mod
+TRIGGER;RELATED=START:-PT5M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+ result = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DTEND;VALUE=DATE:20080602
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+DTSTAMP:20080601T120000Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY;COUNT=5
+END:VEVENT
+BEGIN:X-CALENDARSERVER-PERUSER
+UID:12345-67890
+X-CALENDARSERVER-PERUSER-UID:user01
+BEGIN:X-CALENDARSERVER-PERINSTANCE
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-1mod
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:X-CALENDARSERVER-PERINSTANCE
+BEGIN:X-CALENDARSERVER-PERINSTANCE
+RECURRENCE-ID;VALUE=DATE:20080602
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-1mod
+TRIGGER;RELATED=START:-PT5M
+END:VALARM
+END:X-CALENDARSERVER-PERINSTANCE
+END:X-CALENDARSERVER-PERUSER
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ filtered = PerUserDataFilter("user01").merge(newdata, None)
+ self.assertEqual(str(filtered), result)
+ unfiltered = PerUserDataFilter("user01").filter(filtered)
+ self.assertEqual(str(unfiltered), newdata)
+
+
+ def test_merge_peruser_compact(self):
+
+ newdata = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T110000Z
+DTEND:20080601T120000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+DTSTAMP:20080601T120000Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY;COUNT=5
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-1mod
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T110000Z
+DTSTART:20080602T120000Z
+DTEND:20080602T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+DTSTAMP:20080601T120000Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-1mod
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+ result = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T110000Z
+DTEND:20080601T120000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+DTSTAMP:20080601T120000Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY;COUNT=5
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T110000Z
+DTSTART:20080602T120000Z
+DTEND:20080602T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+DTSTAMP:20080601T120000Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+END:VEVENT
+BEGIN:X-CALENDARSERVER-PERUSER
+UID:12345-67890
+X-CALENDARSERVER-PERUSER-UID:user01
+BEGIN:X-CALENDARSERVER-PERINSTANCE
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-1mod
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:X-CALENDARSERVER-PERINSTANCE
+END:X-CALENDARSERVER-PERUSER
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ filtered = PerUserDataFilter("user01").merge(newdata, None)
+ self.assertEqual(str(filtered), result)
+ unfiltered = PerUserDataFilter("user01").filter(filtered)
+ self.assertEqual(str(unfiltered), newdata)
+
+
+ def test_merge_peruser_all_day_compact(self):
+
+ newdata = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DTEND;VALUE=DATE:20080602
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+DTSTAMP:20080601T120000Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY;COUNT=5
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-1mod
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID;VALUE=DATE:20080602
+DTSTART;VALUE=DATE:20080602
+DTEND;VALUE=DATE:20080603
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+DTSTAMP:20080601T120000Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+SUMMARY:Test
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-1mod
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+ result = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DTEND;VALUE=DATE:20080602
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+DTSTAMP:20080601T120000Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY;COUNT=5
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID;VALUE=DATE:20080602
+DTSTART;VALUE=DATE:20080602
+DTEND;VALUE=DATE:20080603
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+DTSTAMP:20080601T120000Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+SUMMARY:Test
+END:VEVENT
+BEGIN:X-CALENDARSERVER-PERUSER
+UID:12345-67890
+X-CALENDARSERVER-PERUSER-UID:user01
+BEGIN:X-CALENDARSERVER-PERINSTANCE
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-1mod
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:X-CALENDARSERVER-PERINSTANCE
+END:X-CALENDARSERVER-PERUSER
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ filtered = PerUserDataFilter("user01").merge(newdata, None)
+ self.assertEqual(str(filtered), result)
+ unfiltered = PerUserDataFilter("user01").filter(filtered)
+ self.assertEqual(str(unfiltered), newdata)
+
+
+ def test_merge_both_compact(self):
+
+ newdata = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T110000Z
+DTEND:20080601T120000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+DTSTAMP:20080601T120000Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY;COUNT=5
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-1mod
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T110000Z
+DTSTART:20080602T110000Z
+DTEND:20080602T120000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+DTSTAMP:20080601T120000Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-1mod
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+ result = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T110000Z
+DTEND:20080601T120000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+DTSTAMP:20080601T120000Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY;COUNT=5
+END:VEVENT
+BEGIN:X-CALENDARSERVER-PERUSER
+UID:12345-67890
+X-CALENDARSERVER-PERUSER-UID:user01
+BEGIN:X-CALENDARSERVER-PERINSTANCE
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-1mod
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:X-CALENDARSERVER-PERINSTANCE
+END:X-CALENDARSERVER-PERUSER
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ unfiltered_result = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T110000Z
+DTEND:20080601T120000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+DTSTAMP:20080601T120000Z
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY;COUNT=5
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-1mod
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ filtered = PerUserDataFilter("user01").merge(newdata, None)
+ self.assertEqual(str(filtered), result)
+ unfiltered = PerUserDataFilter("user01").filter(filtered)
+ self.assertEqual(str(unfiltered), unfiltered_result)
Modified: CalendarServer/trunk/twistedcaldav/ical.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/ical.py 2012-06-08 01:10:12 UTC (rev 9341)
+++ CalendarServer/trunk/twistedcaldav/ical.py 2012-06-08 01:11:47 UTC (rev 9342)
@@ -1139,7 +1139,7 @@
return True
return False
- def deriveInstance(self, rid, allowCancelled=False):
+ def deriveInstance(self, rid, allowCancelled=False, newcomp=None):
"""
Derive an instance from the master component that has the provided RECURRENCE-ID, but
with all other properties, components etc from the master. If the requested override is
@@ -1154,6 +1154,9 @@
@return: L{Component} for newly derived instance, or None if not valid override
"""
+ if allowCancelled and newcomp is not None:
+ raise ValueError("Cannot re-use master component with allowCancelled")
+
# Must have a master component
master = self.masterComponent()
if master is None:
@@ -1188,22 +1191,17 @@
rrules = master.properties("RRULE")
if len(tuple(rrules)):
instances = self.cacheExpandedTimeRanges(rid)
- rids = set([instances[key].rid for key in instances])
instance_rid = normalizeForIndex(rid)
- if instance_rid not in rids:
+ if str(instance_rid) not in instances.instances:
# No match to a valid RRULE instance
return None
else:
# No RRULE and no match to an RDATE => error
return None
- # Create the derived instance
- newcomp = master.duplicate()
-
- # Strip out unwanted recurrence properties
- for property in tuple(newcomp.properties()):
- if property.name() in ("RRULE", "RDATE", "EXRULE", "EXDATE", "RECURRENCE-ID",):
- newcomp.removeProperty(property)
+ # If we were fed an already derived component, use that, otherwise make a new one
+ if newcomp is None:
+ newcomp = self.masterDerived()
# New DTSTART is the RECURRENCE-ID we are deriving but adjusted to the
# original DTSTART's localtime
@@ -1223,7 +1221,7 @@
if newcomp.hasProperty("DTEND"):
dtend.setValue(newdtstartValue + oldduration)
- newcomp.addProperty(Property("RECURRENCE-ID", dtstart.value(), params={}))
+ newcomp.replaceProperty(Property("RECURRENCE-ID", dtstart.value(), params={}))
if didCancel:
newcomp.replaceProperty(Property("STATUS", "CANCELLED"))
@@ -1232,7 +1230,30 @@
newcomp._pycalendar.finalise()
return newcomp
+
+ def masterDerived(self):
+ """
+ Generate a component from the master instance that can be fed repeatedly to
+ deriveInstance in the case where the result of deriveInstance is not going
+ to be inserted into the component. This provides an optimization for avoiding
+ unnecessary .duplicate() calls on the master for each deriveInstance.
+ """
+
+ # Must have a master component
+ master = self.masterComponent()
+ if master is None:
+ return None
+
+ # Create the derived instance
+ newcomp = master.duplicate()
+
+ # Strip out unwanted recurrence properties
+ for property in tuple(newcomp.properties()):
+ if property.name() in ("RRULE", "RDATE", "EXRULE", "EXDATE", "RECURRENCE-ID",):
+ newcomp.removeProperty(property)
+ return newcomp
+
def validInstances(self, rids, ignoreInvalidInstances=False):
"""
Test whether the specified recurrence-ids are valid instances in this event.
Modified: CalendarServer/trunk/twistedcaldav/test/test_icalendar.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_icalendar.py 2012-06-08 01:10:12 UTC (rev 9341)
+++ CalendarServer/trunk/twistedcaldav/test/test_icalendar.py 2012-06-08 01:11:47 UTC (rev 9342)
@@ -4200,6 +4200,59 @@
self.assertEqual(ical.cachedInstances.limit, oldLimit)
+ def test_derive_instance_with_master_passed_in(self):
+ """
+ Test that derivation of instances only triggers an instance cache re-expansion when it
+ goes past the end of the last cache.
+ """
+
+ event = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20090101T080000Z
+DTEND:20090101T090000Z
+DTSTAMP:20080601T120000Z
+RRULE:FREQ=DAILY
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ derived1 = """BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20090102T080000Z
+DTSTART:20090102T080000Z
+DTEND:20090102T090000Z
+DTSTAMP:20080601T120000Z
+END:VEVENT
+""".replace("\n", "\r\n")
+
+ derived2 = """BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20090203T080000Z
+DTSTART:20090203T080000Z
+DTEND:20090203T090000Z
+DTSTAMP:20080601T120000Z
+END:VEVENT
+""".replace("\n", "\r\n")
+
+ ical = Component.fromString(event)
+ masterDerived = ical.masterDerived()
+
+ # Derive one day apart - no re-cache
+ result = ical.deriveInstance(PyCalendarDateTime(2009, 1, 2, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)), newcomp=masterDerived)
+ self.assertEqual(str(result), derived1)
+
+ result = ical.deriveInstance(PyCalendarDateTime(2009, 2, 3, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)), newcomp=masterDerived)
+ self.assertEqual(str(result), derived2)
+
+ result = ical.deriveInstance(PyCalendarDateTime(2009, 3, 3, 9, 0, 0, tzid=PyCalendarTimezone(utc=True)), newcomp=masterDerived)
+ self.assertEqual(result, None)
+
+ self.assertEqual(str(ical), event)
+
+
def test_truncate_recurrence(self):
data = (
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120607/d2930eb7/attachment-0001.html>
More information about the calendarserver-changes
mailing list