[CalendarServer-changes] [13787] CalendarServer/branches/release/CalendarServer-5.3-dev
source_changes at macosforge.org
source_changes at macosforge.org
Thu Jul 24 08:57:13 PDT 2014
Revision: 13787
http://trac.calendarserver.org//changeset/13787
Author: cdaboo at apple.com
Date: 2014-07-24 08:57:13 -0700 (Thu, 24 Jul 2014)
Log Message:
-----------
Don't update the TIME_RANGE table when there are no changes to it.
Modified Paths:
--------------
CalendarServer/branches/release/CalendarServer-5.3-dev/twistedcaldav/stdconfig.py
CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/scheduling/icaldiff.py
CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/scheduling/processing.py
CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/sql.py
CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/test/test_sql.py
Modified: CalendarServer/branches/release/CalendarServer-5.3-dev/twistedcaldav/stdconfig.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-5.3-dev/twistedcaldav/stdconfig.py 2014-07-24 15:56:17 UTC (rev 13786)
+++ CalendarServer/branches/release/CalendarServer-5.3-dev/twistedcaldav/stdconfig.py 2014-07-24 15:57:13 UTC (rev 13787)
@@ -1012,6 +1012,7 @@
"FreeBusyIndexExpandAheadDays": 365,
"FreeBusyIndexExpandMaxDays": 5 * 365,
"FreeBusyIndexDelayedExpand": True,
+ "FreeBusyIndexSmartUpdate": True,
# The RootResource uses a twext property store. Specify the class here
"RootResourcePropStoreClass": "twext.web2.dav.xattrprops.xattrPropertyStore",
Modified: CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/scheduling/icaldiff.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/scheduling/icaldiff.py 2014-07-24 15:56:17 UTC (rev 13786)
+++ CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/scheduling/icaldiff.py 2014-07-24 15:57:13 UTC (rev 13787)
@@ -692,7 +692,7 @@
return partstatChanged
- def whatIsDifferent(self):
+ def whatIsDifferent(self, isiTip=True):
"""
Compare the two calendar objects in their entirety and return a list of properties
and PARTSTAT parameters that are different.
@@ -721,7 +721,7 @@
for key in (oldset & newset):
component1 = oldmap[key]
component2 = newmap[key]
- self._diffComponents(component1, component2, rids)
+ self._diffComponents(component1, component2, rids, isiTip)
# Now verify that each additional component in oldset matches a derived component in newset
for key in oldset - newset:
@@ -729,7 +729,7 @@
newcomponent = self.newcalendar.deriveInstance(key[2])
if newcomponent is None:
continue
- self._diffComponents(oldcomponent, newcomponent, rids)
+ self._diffComponents(oldcomponent, newcomponent, rids, isiTip)
# Now verify that each additional component in oldset matches a derived component in newset
for key in newset - oldset:
@@ -737,24 +737,59 @@
if oldcomponent is None:
continue
newcomponent = newmap[key]
- self._diffComponents(oldcomponent, newcomponent, rids)
+ self._diffComponents(oldcomponent, newcomponent, rids, isiTip)
return rids
- def _componentDuplicateAndNormalize(self, comp):
+ TRPROPS = frozenset((
+ "DTSTART",
+ "DTEND",
+ "DURATION",
+ "DUE",
+ "RECURRENCE-ID",
+ "RRULE",
+ "RDATE",
+ "EXDATE",
+ "STATUS",
+ "TRANSP",
+ "X-APPLE-TRAVEL-START",
+ "X-APPLE-TRAVEL-DURATION",
+ "X-APPLE-TRAVEL-RETURN",
+ "X-APPLE-TRAVEL-RETURN-DURATION",
+ ))
+
+ def timeRangeDifference(self):
+ """
+ Is there a difference between the two components that implies a change to the time or
+ transparency/status of any instance.
+
+ @return: L{True} if there is such a change, L{False} otherwise
+ @rtype: L{bool}
+ """
+
+ for props in self.whatIsDifferent(isiTip=False).values():
+ props = frozenset(props.keys())
+ if props & self.TRPROPS:
+ return True
+ else:
+ return False
+
+
+ def _componentDuplicateAndNormalize(self, comp, isiTip=True):
comp = comp.duplicate()
comp.normalizePropertyValueLists("EXDATE")
- comp.removePropertyParameters("ORGANIZER", ("SCHEDULE-STATUS",))
- comp.removePropertyParameters("ATTENDEE", ("SCHEDULE-STATUS", "SCHEDULE-FORCE-SEND",))
comp.removeAlarms()
comp.normalizeAll()
comp.normalizeAttachments()
- iTipGenerator.prepareSchedulingMessage(comp, reply=True)
+ if isiTip:
+ comp.removePropertyParameters("ORGANIZER", ("SCHEDULE-STATUS",))
+ comp.removePropertyParameters("ATTENDEE", ("SCHEDULE-STATUS", "SCHEDULE-FORCE-SEND",))
+ iTipGenerator.prepareSchedulingMessage(comp, reply=True)
return comp
- def _diffComponents(self, comp1, comp2, rids):
+ def _diffComponents(self, comp1, comp2, rids, isiTip=True):
assert isinstance(comp1, Component) and isinstance(comp2, Component)
@@ -763,8 +798,8 @@
return
# Duplicate then normalize for comparison
- comp1 = self._componentDuplicateAndNormalize(comp1)
- comp2 = self._componentDuplicateAndNormalize(comp2)
+ comp1 = self._componentDuplicateAndNormalize(comp1, isiTip)
+ comp2 = self._componentDuplicateAndNormalize(comp2, isiTip)
# Diff all the properties
propdiff = set(comp1.properties()) ^ set(comp2.properties())
@@ -773,7 +808,6 @@
propsChanged = {}
for prop in propdiff:
if prop.name() in (
- "TRANSP",
"DTSTAMP",
"CREATED",
"LAST-MODIFIED",
Modified: CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/scheduling/processing.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/scheduling/processing.py 2014-07-24 15:56:17 UTC (rev 13786)
+++ CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/scheduling/processing.py 2014-07-24 15:57:13 UTC (rev 13787)
@@ -162,7 +162,7 @@
self.recipient_calendar_resource = None
calendar_resource = (yield getCalendarObjectForRecord(self.txn, self.recipient.principal, self.uid))
if calendar_resource:
- self.recipient_calendar = (yield calendar_resource.componentForUser(self.recipient.principal.uid))
+ self.recipient_calendar = (yield calendar_resource.componentForUser(self.recipient.principal.uid)).duplicate()
self.recipient_calendar_resource = calendar_resource
Modified: CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/sql.py 2014-07-24 15:56:17 UTC (rev 13786)
+++ CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/sql.py 2014-07-24 15:57:13 UTC (rev 13787)
@@ -58,6 +58,7 @@
from twistedcaldav.memcacher import Memcacher
from txdav.base.propertystore.base import PropertyName
+from txdav.caldav.datastore.scheduling.icaldiff import iCalDiff
from txdav.caldav.datastore.scheduling.icalsplitter import iCalSplitter
from txdav.caldav.datastore.scheduling.implicit import ImplicitScheduler
from txdav.caldav.datastore.util import AttachmentRetrievalTransport, \
@@ -1746,7 +1747,7 @@
@inlineCallbacks
- def preservePrivateComments(self, component, inserting):
+ def preservePrivateComments(self, component, inserting, internal_state):
"""
Check for private comments on the old resource and the new resource and re-insert
ones that are lost.
@@ -1765,7 +1766,7 @@
"X-CALENDARSERVER-ATTENDEE-COMMENT",
))
- if old_has_private_comments and not new_has_private_comments:
+ if old_has_private_comments and not new_has_private_comments and internal_state == ComponentUpdateState.NORMAL:
# Transfer old comments to new calendar
log.debug("Organizer private comment properties were entirely removed by the client. Restoring existing properties.")
old_calendar = (yield self.componentForUser())
@@ -1779,7 +1780,7 @@
# to raise an error to prevent that so the client bugs can be tracked down.
# Look for properties with duplicate "X-CALENDARSERVER-ATTENDEE-REF" values in the same component
- if component.hasDuplicatePrivateComments(doFix=config.RemoveDuplicatePrivateComments):
+ if component.hasDuplicatePrivateComments(doFix=config.RemoveDuplicatePrivateComments) and internal_state == ComponentUpdateState.NORMAL:
raise DuplicatePrivateCommentsError("Duplicate X-CALENDARSERVER-ATTENDEE-COMMENT properties present.")
@@ -2196,7 +2197,7 @@
self.validAccess(component, inserting, internal_state)
# Preserve private comments
- yield self.preservePrivateComments(component, inserting)
+ yield self.preservePrivateComments(component, inserting, internal_state)
managed_copied, managed_removed = (yield self.resourceCheckAttachments(component, inserting))
@@ -2215,7 +2216,7 @@
yield self._lockUID(component, inserting, internal_state)
# Preserve private comments
- yield self.preservePrivateComments(component, inserting)
+ yield self.preservePrivateComments(component, inserting, internal_state)
# Fix broken VTODOs
yield self.replaceMissingToDoProperties(component, inserting, internal_state)
@@ -2259,6 +2260,13 @@
if did_implicit_action:
self._componentChanged = True
+ if not hasattr(self, "tr_change"):
+ if inserting or hasattr(component, "noInstanceIndexing") or not config.FreeBusyIndexSmartUpdate:
+ self.tr_change = None
+ else:
+ oldcomponent = yield self.componentForUser()
+ self.tr_change = iCalDiff(oldcomponent, component, False).timeRangeDifference()
+
# Always do the per-user data merge right before we store
component = (yield self.mergePerUserData(component, inserting))
@@ -2331,7 +2339,12 @@
# In some cases there is no need to remove/rebuild the instance index because we know no time or
# freebusy related properties have changed (e.g. an attendee reply and refresh). In those cases
# the component will have a special attribute present to let us know to suppress the instance indexing.
- instanceIndexingRequired = not getattr(component, "noInstanceIndexing", False) or inserting or reCreate
+ if inserting or reCreate:
+ instanceIndexingRequired = True
+ elif getattr(component, "noInstanceIndexing", False):
+ instanceIndexingRequired = False
+ else:
+ instanceIndexingRequired = getattr(self, "tr_change", True) in (None, True)
if instanceIndexingRequired:
Modified: CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/test/test_sql.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/test/test_sql.py 2014-07-24 15:56:17 UTC (rev 13786)
+++ CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/test/test_sql.py 2014-07-24 15:57:13 UTC (rev 13787)
@@ -52,6 +52,7 @@
from txdav.caldav.datastore.scheduling.scheduler import ScheduleResponseQueue
from txdav.caldav.datastore.scheduling.implicit import ImplicitScheduler
from txdav.caldav.datastore.scheduling.itip import iTIPRequestStatus
+from txdav.caldav.datastore.sql import CalendarObject
from txdav.caldav.datastore.test.common import CommonTests as CalendarCommonTests, \
test_event_text, OTHER_HOME_UID
from txdav.caldav.datastore.test.test_file import setUpCalendarStore
@@ -1456,6 +1457,7 @@
# Re-add event with re-indexing
calendar = yield self.calendarUnderTest()
calendarObject = yield self.calendarObjectUnderTest(name="indexing.ics")
+ calendarObject.tr_change = True
yield calendarObject.setComponent(component)
instances2 = yield calendarObject.instances()
self.assertNotEqual(
@@ -6321,3 +6323,572 @@
cobjs = yield cal.calendarObjects()
self.assertEqual(len(cobjs), 1)
yield self.failUnlessFailure(cobjs[0].splitAt(PyCalendarDateTime.parseText("%(now_fwd25)s" % self.subs)), InvalidSplit)
+
+
+
+class TimeRangeUpdateOptimization(CommonCommonTests, unittest.TestCase):
+ """
+ CalendarObject splitting tests
+ """
+
+ EVENT1 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100203T013849Z
+UID:uid1
+DTSTART:{now}T120000Z
+DURATION:PT1H
+SUMMARY:New Event
+DTSTAMP:20100203T013909Z
+END:VEVENT
+END:VCALENDAR
+"""
+
+ EVENT2 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100203T013849Z
+UID:uid1
+DTSTART:{now}T120000Z
+DURATION:PT1H
+SUMMARY:New Event #2
+DTSTAMP:20100203T013909Z
+END:VEVENT
+END:VCALENDAR
+"""
+
+ EVENT3 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100203T013849Z
+UID:uid1
+DTSTART:{now}T130000Z
+DURATION:PT1H
+SUMMARY:New Event
+DTSTAMP:20100203T013909Z
+END:VEVENT
+END:VCALENDAR
+"""
+
+ EVENT4 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100203T013849Z
+UID:uid1
+DTSTART:{now}T120000Z
+DURATION:PT1H
+SUMMARY:New Event
+DTSTAMP:20100203T013909Z
+TRANSP:TRANSPARENT
+END:VEVENT
+END:VCALENDAR
+"""
+
+ EVENT5 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100203T013849Z
+UID:uid1
+DTSTART:{now}T120000Z
+DURATION:PT1H
+SUMMARY:New Event
+STATUS:CANCELLED
+DTSTAMP:20100203T013909Z
+END:VEVENT
+END:VCALENDAR
+"""
+
+ EVENT6 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100203T013849Z
+UID:uid1
+DTSTART:{now}T120000Z
+DURATION:PT1H
+SUMMARY:New Event
+DTSTAMP:20100203T013909Z
+X-APPLE-TRAVEL-DURATION;VALUE=DURATION:PT1H
+END:VEVENT
+END:VCALENDAR
+"""
+
+ EVENT7 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100203T013849Z
+UID:uid1
+DTSTART:{now}T120000Z
+DURATION:PT1H
+SUMMARY:New Event
+DTSTAMP:20100203T013909Z
+RRULE:FREQ=DAILY
+END:VEVENT
+END:VCALENDAR
+"""
+
+ EVENT8 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100203T013849Z
+UID:uid1
+DTSTART:{now}T120000Z
+DURATION:PT1H
+SUMMARY:New Event
+DTSTAMP:20100203T013909Z
+RRULE:FREQ=DAILY;COUNT=10
+END:VEVENT
+END:VCALENDAR
+"""
+
+ EVENT9 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100203T013849Z
+UID:uid1
+DTSTART:{now}T120000Z
+DURATION:PT1H
+SUMMARY:New Event
+DTSTAMP:20100203T013909Z
+RRULE:FREQ=DAILY
+EXDATE:{now}T120000Z
+END:VEVENT
+END:VCALENDAR
+"""
+
+ EVENT10 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100203T013849Z
+UID:uid1
+DTSTART:{now}T120000Z
+DURATION:PT1H
+SUMMARY:New Event
+DTSTAMP:20100203T013909Z
+RRULE:FREQ=DAILY
+RDATE:{now}T150000Z
+END:VEVENT
+END:VCALENDAR
+"""
+
+
+ @inlineCallbacks
+ def setUp(self):
+ yield super(TimeRangeUpdateOptimization, self).setUp()
+ self._sqlCalendarStore = yield buildCalendarStore(self, self.notifierFactory)
+ yield self.populate()
+
+ self.now = PyCalendarDateTime.getNowUTC()
+ self.now.setDateOnly(True)
+
+ self.trcount = 0
+ base_addInstances = CalendarObject._addInstances
+ def __addInstances(*args):
+ self.trcount += 1
+ return base_addInstances(*args)
+ self.patch(CalendarObject, "_addInstances", __addInstances)
+
+ self.patch(config, "FreeBusyIndexDelayedExpand", False)
+ self.patch(config, "FreeBusyIndexSmartUpdate", True)
+
+
+ @inlineCallbacks
+ def populate(self):
+ yield populateCalendarsFrom(self.requirements, self.storeUnderTest())
+ self.notifierFactory.reset()
+
+
+ def storeUnderTest(self):
+ """
+ Create and return a L{CalendarStore} for testing.
+ """
+ return self._sqlCalendarStore
+
+
+ @property
+ def requirements(self):
+ return {
+ "home1": {
+ "calendar_1": {},
+ },
+ "user01": {
+ "calendar": {},
+ "inbox": {},
+ },
+ "user02": {
+ "calendar": {},
+ "inbox": {},
+ },
+ }
+
+
+ @inlineCallbacks
+ def test_initalPUT(self):
+ """
+ Test that initial PUT causes a TIME_RANGE update
+ """
+
+ # First PUT causes T-R change
+ cal = yield self.calendarUnderTest()
+ yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT1.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 1)
+
+
+ @inlineCallbacks
+ def test_updatePUT_withoutTRChange(self):
+ """
+ Test that second PUT withe time change causes a TIME_RANGE update
+ """
+
+ # First PUT causes T-R change
+ cal = yield self.calendarUnderTest()
+ yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT1.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 1)
+
+ # Second PUT does not cause T-R change
+ cobj = yield self.calendarObjectUnderTest()
+ yield cobj.setComponent(Component.fromString(self.EVENT2.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 1)
+
+
+ @inlineCallbacks
+ def test_updatePUT_withoutOptimization(self):
+ """
+ Test that second PUT withe time change causes a TIME_RANGE update
+ """
+
+ self.patch(config, "FreeBusyIndexSmartUpdate", False)
+
+ # First PUT causes T-R change
+ cal = yield self.calendarUnderTest()
+ yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT1.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 1)
+
+ # Second PUT does cause T-R change
+ cobj = yield self.calendarObjectUnderTest()
+ yield cobj.setComponent(Component.fromString(self.EVENT2.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 2)
+
+
+ @inlineCallbacks
+ def test_updatePUT_withTRChange(self):
+ """
+ Test that second PUT withe time change causes a TIME_RANGE update
+ """
+
+ # First PUT causes T-R change
+ cal = yield self.calendarUnderTest()
+ yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT1.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 1)
+
+ # Second PUT causes T-R change
+ cobj = yield self.calendarObjectUnderTest()
+ yield cobj.setComponent(Component.fromString(self.EVENT3.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 2)
+
+
+ @inlineCallbacks
+ def test_updatePUT_withTranspChange(self):
+ """
+ Test that second PUT withe time change causes a TIME_RANGE update
+ """
+
+ # First PUT causes T-R change
+ cal = yield self.calendarUnderTest()
+ yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT1.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 1)
+
+ # Second PUT causes T-R change
+ cobj = yield self.calendarObjectUnderTest()
+ yield cobj.setComponent(Component.fromString(self.EVENT4.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 2)
+
+
+ @inlineCallbacks
+ def test_updatePUT_withStatusChange(self):
+ """
+ Test that second PUT withe time change causes a TIME_RANGE update
+ """
+
+ # First PUT causes T-R change
+ cal = yield self.calendarUnderTest()
+ yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT1.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 1)
+
+ # Second PUT causes T-R change
+ cobj = yield self.calendarObjectUnderTest()
+ yield cobj.setComponent(Component.fromString(self.EVENT5.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 2)
+
+
+ @inlineCallbacks
+ def test_updatePUT_withTravelTimeChange(self):
+ """
+ Test that second PUT withe time change causes a TIME_RANGE update
+ """
+
+ # First PUT causes T-R change
+ cal = yield self.calendarUnderTest()
+ yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT1.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 1)
+
+ # Second PUT causes T-R change
+ cobj = yield self.calendarObjectUnderTest()
+ yield cobj.setComponent(Component.fromString(self.EVENT6.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 2)
+
+
+ @inlineCallbacks
+ def test_updatePUT_withRRULEChange(self):
+ """
+ Test that second PUT withe time change causes a TIME_RANGE update
+ """
+
+ # First PUT causes T-R change
+ cal = yield self.calendarUnderTest()
+ yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT7.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 1)
+
+ # Second PUT causes T-R change
+ cobj = yield self.calendarObjectUnderTest()
+ yield cobj.setComponent(Component.fromString(self.EVENT8.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 2)
+
+
+ @inlineCallbacks
+ def test_updatePUT_withEXDATEAdd(self):
+ """
+ Test that second PUT withe time change causes a TIME_RANGE update
+ """
+
+ # First PUT causes T-R change
+ cal = yield self.calendarUnderTest()
+ yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT7.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 1)
+
+ # Second PUT causes T-R change
+ cobj = yield self.calendarObjectUnderTest()
+ yield cobj.setComponent(Component.fromString(self.EVENT9.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 2)
+
+
+ @inlineCallbacks
+ def test_updatePUT_withRDATEAdd(self):
+ """
+ Test that second PUT withe time change causes a TIME_RANGE update
+ """
+
+ # First PUT causes T-R change
+ cal = yield self.calendarUnderTest()
+ yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT7.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 1)
+
+ # Second PUT causes T-R change
+ cobj = yield self.calendarObjectUnderTest()
+ yield cobj.setComponent(Component.fromString(self.EVENT10.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 2)
+
+
+ INVITE1 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100203T013849Z
+UID:uid1
+DTSTART:{now}T120000Z
+DURATION:PT1H
+SUMMARY:New Event
+DTSTAMP:20100203T013909Z
+ORGANIZER:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:user02 at example.com
+END:VEVENT
+END:VCALENDAR
+"""
+
+ INVITE2 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100203T013849Z
+UID:uid1
+DTSTART:{now}T120000Z
+DURATION:PT1H
+SUMMARY:New Event
+DTSTAMP:20100203T013909Z
+ORGANIZER:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user02 at example.com
+END:VEVENT
+END:VCALENDAR
+"""
+
+ INVITE3 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100203T013849Z
+UID:uid1
+DTSTART:{now}T120000Z
+DURATION:PT1H
+SUMMARY:New Event #2
+DTSTAMP:20100203T013909Z
+ORGANIZER:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user02 at example.com
+END:VEVENT
+END:VCALENDAR
+"""
+
+ INVITE4 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100203T013849Z
+UID:uid1
+DTSTART:{now}T140000Z
+DURATION:PT1H
+SUMMARY:New Event #2
+DTSTAMP:20100203T013909Z
+ORGANIZER:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user02 at example.com
+END:VEVENT
+END:VCALENDAR
+"""
+
+ @inlineCallbacks
+ def test_schedulingPUT(self):
+ """
+ Test that second PUT withe time change causes a TIME_RANGE update
+ """
+
+ # First PUT causes T-R change
+ cal = yield self.calendarUnderTest(home="user01", name="calendar")
+ yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.INVITE1.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 3)
+
+ # Attendee reply does not cause T-R change (except for inbox item and attendee resource transp change)
+ cal = yield self.calendarUnderTest(home="user02", name="calendar")
+ cobjs = yield cal.calendarObjects()
+ self.assertEqual(len(cobjs), 1)
+ yield cobjs[0].setComponent(Component.fromString(self.INVITE2.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 5)
+
+ # Organizer summary change does not cause T-R change (except for inbox item)
+ cobj = yield self.calendarObjectUnderTest(home="user01", calendar_name="calendar")
+ yield cobj.setComponent(Component.fromString(self.INVITE3.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 6)
+
+ # Organizer dtstart change causes T-R change
+ cobj = yield self.calendarObjectUnderTest(home="user01", calendar_name="calendar")
+ yield cobj.setComponent(Component.fromString(self.INVITE4.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 9)
+
+
+ @inlineCallbacks
+ def test_schedulingPUT_withoutOptimization(self):
+ """
+ Test that second PUT withe time change causes a TIME_RANGE update
+ """
+
+ self.patch(config, "FreeBusyIndexSmartUpdate", False)
+
+ # First PUT causes T-R change
+ cal = yield self.calendarUnderTest(home="user01", name="calendar")
+ yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.INVITE1.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 3)
+
+ # Attendee reply does cause T-R change (except for organizer update)
+ cal = yield self.calendarUnderTest(home="user02", name="calendar")
+ cobjs = yield cal.calendarObjects()
+ self.assertEqual(len(cobjs), 1)
+ yield cobjs[0].setComponent(Component.fromString(self.INVITE2.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 5)
+
+ # Organizer summary change causes T-R change
+ cobj = yield self.calendarObjectUnderTest(home="user01", calendar_name="calendar")
+ yield cobj.setComponent(Component.fromString(self.INVITE3.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 8)
+
+ # Organizer dtstart change causes T-R change
+ cobj = yield self.calendarObjectUnderTest(home="user01", calendar_name="calendar")
+ yield cobj.setComponent(Component.fromString(self.INVITE4.format(now=self.now.getText())))
+ yield self.commit()
+
+ self.assertEqual(self.trcount, 11)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140724/66618cdf/attachment-0001.html>
More information about the calendarserver-changes
mailing list