[CalendarServer-changes] [13341] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Sun Apr 20 22:11:50 PDT 2014


Revision: 13341
          http://trac.calendarserver.org//changeset/13341
Author:   gaya at apple.com
Date:     2014-04-20 22:11:50 -0700 (Sun, 20 Apr 2014)
Log Message:
-----------
Fix multi-group group attendees. Mostly fix group attendees when group disappears from directory. Fix tests.

Modified Paths:
--------------
    CalendarServer/trunk/twistedcaldav/ical.py
    CalendarServer/trunk/txdav/common/datastore/sql.py
    CalendarServer/trunk/txdav/who/groups.py
    CalendarServer/trunk/txdav/who/test/accounts/groupAttendeeAccounts.xml
    CalendarServer/trunk/txdav/who/test/test_group_attendees.py

Modified: CalendarServer/trunk/twistedcaldav/ical.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/ical.py	2014-04-20 23:23:23 UTC (rev 13340)
+++ CalendarServer/trunk/twistedcaldav/ical.py	2014-04-21 05:11:50 UTC (rev 13341)
@@ -3425,7 +3425,7 @@
                             attendeeProp.removeParameterValue("MEMBER", groupCUA)
                             if not attendeeProp.parameterValues("MEMBER"):
                                 component.removeProperty(attendeeProp)
-                                changed = True
+                            changed = True
                     else:
                         if attendeeProp.value() in memberCUAs:
                             attendeeProp.setParameter("MEMBER", parameterValues + (groupCUA,))
@@ -3438,20 +3438,32 @@
 
         changed = False
         allMemberCUAs = set()
+        nonemptyGroupCUAs = set()
         for groupCUA, memberAttendeeProps in groupCUAToAttendeeMemberPropMap.iteritems():
             changed |= self._reconcileGroupAttendee(groupCUA, memberAttendeeProps)
             allMemberCUAs |= set([memberAttendeeProp.value() for memberAttendeeProp in memberAttendeeProps])
+            if memberAttendeeProps:
+                nonemptyGroupCUAs.add(groupCUA)
 
         # remove orphans
         for component in self.subcomponents():
             if component.name() in ignoredComponents:
                 continue
 
-            for attendeeMemberProp in component.properties("ATTENDEE"):
-                if attendeeMemberProp.hasParameter("MEMBER"):
-                    attendeeCUA = attendeeMemberProp.value()
-                    if attendeeCUA not in allMemberCUAs:
-                        component.removeProperty(attendeeMemberProp)
+            for attendeeProp in tuple(component.properties("ATTENDEE")):
+                if attendeeProp.hasParameter("MEMBER"):
+                    attendeeCUA = attendeeProp.value()
+                    if attendeeCUA in allMemberCUAs:
+                        # remove orphan member values
+                        parameterValues = tuple(attendeeProp.parameterValues("MEMBER"))
+                        for orphanGroupCUA in set(parameterValues) - nonemptyGroupCUAs:
+                            attendeeProp.removeParameterValue("MEMBER", orphanGroupCUA)
+                            if not attendeeProp.parameterValues("MEMBER"):
+                                component.removeProperty(attendeeProp)
+                            changed = True
+                    else:
+                        # remove orphaned member property
+                        component.removeProperty(attendeeProp)
                         changed = True
 
         return changed

Modified: CalendarServer/trunk/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql.py	2014-04-20 23:23:23 UTC (rev 13340)
+++ CalendarServer/trunk/txdav/common/datastore/sql.py	2014-04-21 05:11:50 UTC (rev 13341)
@@ -1054,7 +1054,7 @@
 
 
     @inlineCallbacks
-    def groupByUID(self, groupUID):
+    def groupByUID(self, groupUID, create=True):
         """
         Return or create a record for the group UID.
 
@@ -1075,7 +1075,7 @@
                 results[0][2],  # membership hash
                 results[0][3],  # modified timestamp
             ))
-        else:
+        elif create:
             savepoint = SavepointAction("groupByUID")
             yield savepoint.acquire(self)
             try:
@@ -1112,6 +1112,8 @@
                     ))
                 else:
                     raise
+        else:
+            returnValue((None, None, None, None))
 
 
     @inlineCallbacks

Modified: CalendarServer/trunk/txdav/who/groups.py
===================================================================
--- CalendarServer/trunk/txdav/who/groups.py	2014-04-20 23:23:23 UTC (rev 13340)
+++ CalendarServer/trunk/txdav/who/groups.py	2014-04-21 05:11:50 UTC (rev 13341)
@@ -306,41 +306,52 @@
             WorkProposal is returned for tests
         """
         self.log.debug("Faulting in group: {g}", g=groupUID)
-        wp = None
         record = (yield self.directory.recordWithUID(groupUID))
         if record is None:
-            # FIXME: the group has disappeared from the directory.
-            # How do we want to handle this?
+            # the group has disappeared from the directory - OK
+            # FIXME: If group reappears, it will not be used in existing events
             self.log.info("Group has disappeared: {g}", g=groupUID)
         else:
             self.log.debug("Got group record: {u}", u=record.uid)
-            membershipHashContent = hashlib.md5()
-            members = yield record.expandedMembers()
-            members = list(members)
-            members.sort(cmp=lambda x, y: cmp(x.uid, y.uid))
-            for member in members:
-                membershipHashContent.update(str(member.uid))
-            membershipHash = membershipHashContent.hexdigest()
-            groupID, _ignore_cachedName, cachedMembershipHash, _ignore_modified = (
-                yield txn.groupByUID(groupUID)
+
+        groupID, _ignore_cachedName, cachedMembershipHash, _ignore_modified = (
+            yield txn.groupByUID(
+                groupUID,
+                create=(record is not None)
             )
+        )
+        wp = None
+        if groupID:
+            if record is not None:
+                membershipHashContent = hashlib.md5()
+                members = yield record.expandedMembers()
+                members = list(members)
+                members.sort(cmp=lambda x, y: cmp(x.uid, y.uid))
+                for member in members:
+                    membershipHashContent.update(str(member.uid))
+                membershipHash = membershipHashContent.hexdigest()
 
-            if cachedMembershipHash != membershipHash:
-                membershipChanged = True
-                self.log.debug(
-                    "Group '{group}' changed", group=record.fullNames[0]
-                )
-            else:
-                membershipChanged = False
+                if cachedMembershipHash != membershipHash:
+                    membershipChanged = True
+                    self.log.debug(
+                        "Group '{group}' changed", group=record.fullNames[0]
+                    )
+                else:
+                    membershipChanged = False
 
-            yield txn.updateGroup(groupUID, record.fullNames[0], membershipHash)
+                yield txn.updateGroup(groupUID, record.fullNames[0], membershipHash)
 
-            if membershipChanged:
-                newMemberUIDs = set()
-                for member in members:
-                    newMemberUIDs.add(member.uid)
-                yield self.synchronizeMembers(txn, groupID, newMemberUIDs)
+                if membershipChanged:
+                    newMemberUIDs = set()
+                    for member in members:
+                        newMemberUIDs.add(member.uid)
+                    yield self.synchronizeMembers(txn, groupID, newMemberUIDs)
 
+            else:
+                # FIXME: Use schema's delete cascade
+                yield self.synchronizeMembers(txn, groupID, set())
+                yield txn.deleteGroup(groupID)
+
             wp = yield self.scheduleEventReconciliations(txn, groupID)
 
         returnValue(wp)

Modified: CalendarServer/trunk/txdav/who/test/accounts/groupAttendeeAccounts.xml
===================================================================
--- CalendarServer/trunk/txdav/who/test/accounts/groupAttendeeAccounts.xml	2014-04-20 23:23:23 UTC (rev 13340)
+++ CalendarServer/trunk/txdav/who/test/accounts/groupAttendeeAccounts.xml	2014-04-21 05:11:50 UTC (rev 13341)
@@ -115,6 +115,7 @@
 	    <email>group02 at example.com</email>
 	    <member-uid>10000000-0000-0000-0000-000000000006</member-uid>
 	    <member-uid>10000000-0000-0000-0000-000000000007</member-uid>
+	    <member-uid>10000000-0000-0000-0000-000000000008</member-uid>
 	</record>
 	<record type="group">
 	    <short-name>group03</short-name>
@@ -122,6 +123,7 @@
 	    <guid>20000000-0000-0000-0000-000000000003</guid>
 	    <full-name>Group 03</full-name>
 	    <email>group03 at example.com</email>
+	    <member-uid>10000000-0000-0000-0000-000000000007</member-uid>
 	    <member-uid>10000000-0000-0000-0000-000000000008</member-uid>
 	    <member-uid>10000000-0000-0000-0000-000000000009</member-uid>
 	</record>

Modified: CalendarServer/trunk/txdav/who/test/test_group_attendees.py
===================================================================
--- CalendarServer/trunk/txdav/who/test/test_group_attendees.py	2014-04-20 23:23:23 UTC (rev 13340)
+++ CalendarServer/trunk/txdav/who/test/test_group_attendees.py	2014-04-21 05:11:50 UTC (rev 13341)
@@ -18,6 +18,7 @@
     group attendee tests
 """
 
+from twext.who.directory import DirectoryService
 from twext.who.test.test_xml import xmlService
 from twisted.internet.defer import inlineCallbacks, returnValue
 from twisted.trial import unittest
@@ -92,6 +93,13 @@
         self.assertEqual(count, expected_count)
 
 
+    # better error output
+    def _assertICalStrEqual(self, iCalStr1, iCalStr2):
+        if normalize_iCalStr(iCalStr1, sort=True) != normalize_iCalStr(iCalStr2, sort=True):
+            self.assertEqual(normalize_iCalStr(iCalStr1), normalize_iCalStr(iCalStr2))
+            self.assertTrue(False)
+
+
     @inlineCallbacks
     def test_simplePUT(self):
         """
@@ -128,6 +136,7 @@
 ATTENDEE;CN=Group 02;CUTYPE=GROUP;EMAIL=group02 at example.com;RSVP=TRUE;SCHEDULE-STATUS=3.7:urn:x-uid:20000000-0000-0000-0000-000000000002
 ATTENDEE;CN=User 06;EMAIL=user06 at example.com;MEMBER="urn:x-uid:20000000-0000-0000-0000-000000000002";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:10000000-0000-0000-0000-000000000006
 ATTENDEE;CN=User 07;EMAIL=user07 at example.com;MEMBER="urn:x-uid:20000000-0000-0000-0000-000000000002";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:10000000-0000-0000-0000-000000000007
+ATTENDEE;CN=User 08;EMAIL=user08 at example.com;MEMBER="urn:x-uid:20000000-0000-0000-0000-000000000002";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:10000000-0000-0000-0000-000000000008
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 01;EMAIL=user01 at example.com:urn:x-uid:10000000-0000-0000-0000-000000000001
 SUMMARY:event 1
@@ -144,7 +153,7 @@
 
         cobj1 = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="10000000-0000-0000-0000-000000000001")
         vcalendar2 = yield cobj1.component()
-        self.assertEqual(normalize_iCalStr(vcalendar2, sort=True), normalize_iCalStr(data_get_1, sort=True))
+        self._assertICalStrEqual(vcalendar2, data_get_1)
 
         yield self._verifyObjectResourceCount("10000000-0000-0000-0000-000000000006", 1)
         yield self._verifyObjectResourceCount("10000000-0000-0000-0000-000000000007", 1)
@@ -309,7 +318,7 @@
 
         cobj1 = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="10000000-0000-0000-0000-000000000001")
         vcalendar2 = yield cobj1.component()
-        self.assertEqual(normalize_iCalStr(vcalendar2, sort=True), normalize_iCalStr(data_get_1, sort=True))
+        self._assertICalStrEqual(vcalendar2, data_get_1)
 
         yield self._verifyObjectResourceCount("10000000-0000-0000-0000-000000000006", 1)
         yield self._verifyObjectResourceCount("10000000-0000-0000-0000-000000000007", 1)
@@ -361,16 +370,15 @@
 ATTENDEE;CN=Group 01;CUTYPE=GROUP;EMAIL=group01 at example.com;RSVP=TRUE;SCHEDULE-STATUS=3.7:urn:x-uid:20000000-0000-0000-0000-000000000001
 ATTENDEE;CN=Group 02;CUTYPE=GROUP;EMAIL=group02 at example.com;RSVP=TRUE;SCHEDULE-STATUS=3.7:urn:x-uid:20000000-0000-0000-0000-000000000002
 ATTENDEE;CN=Group 03;CUTYPE=GROUP;EMAIL=group03 at example.com;RSVP=TRUE;SCHEDULE-STATUS=3.7:urn:x-uid:20000000-0000-0000-0000-000000000003
-ATTENDEE;CN=User 08;EMAIL=user08 at example.com;MEMBER="urn:x-uid:20000000-0000-0000-0000-000000000003";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:10000000-0000-0000-0000-000000000008
+ATTENDEE;CN=User 06;EMAIL=user06 at example.com;MEMBER="urn:x-uid:20000000-0000-0000-0000-000000000002";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:10000000-0000-0000-0000-000000000006
+ATTENDEE;CN=User 07;EMAIL=user07 at example.com;MEMBER="urn:x-uid:20000000-0000-0000-0000-000000000002","urn:x-uid:20000000-0000-0000-0000-000000000003";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:10000000-0000-0000-0000-000000000007
+ATTENDEE;CN=User 08;EMAIL=user08 at example.com;MEMBER="urn:x-uid:20000000-0000-0000-0000-000000000002","urn:x-uid:20000000-0000-0000-0000-000000000003";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:10000000-0000-0000-0000-000000000008
 ATTENDEE;CN=User 09;EMAIL=user09 at example.com;MEMBER="urn:x-uid:20000000-0000-0000-0000-000000000003";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:10000000-0000-0000-0000-000000000009
-ATTENDEE;CN=User 06;EMAIL=user06 at example.com;MEMBER="urn:x-uid:20000000-0000-0000-0000-000000000002";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:10000000-0000-0000-0000-000000000006
-ATTENDEE;CN=User 07;EMAIL=user07 at example.com;MEMBER="urn:x-uid:20000000-0000-0000-0000-000000000002";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:10000000-0000-0000-0000-000000000007
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 01;EMAIL=user01 at example.com:urn:x-uid:10000000-0000-0000-0000-000000000001
 SUMMARY:event 1
 END:VEVENT
-END:VCALENDAR
-"""
+END:VCALENDAR"""
 
         vcalendar1 = Component.fromString(data_put_1)
         yield calendar.createCalendarObjectWithName("data1.ics", vcalendar1)
@@ -378,7 +386,7 @@
 
         cobj1 = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="10000000-0000-0000-0000-000000000001")
         vcalendar2 = yield cobj1.component()
-        self.assertEqual(normalize_iCalStr(vcalendar2, sort=True), normalize_iCalStr(data_get_1, sort=True))
+        self._assertICalStrEqual(vcalendar2, data_get_1)
 
         yield self._verifyObjectResourceCount("10000000-0000-0000-0000-000000000006", 1)
         yield self._verifyObjectResourceCount("10000000-0000-0000-0000-000000000007", 1)
@@ -386,6 +394,7 @@
         yield self._verifyObjectResourceCount("10000000-0000-0000-0000-000000000009", 1)
 
 
+    #TODO:  Change to multigroup case
     @inlineCallbacks
     def test_groupChange(self):
         """
@@ -524,4 +533,139 @@
         that an attendee in two groups is NOT removed if only one of those groups is removed
         """
 
-        self.fail("FIXME: implement this test")
+        yield self._verifyObjectResourceCount("10000000-0000-0000-0000-000000000006", 0)
+        yield self._verifyObjectResourceCount("10000000-0000-0000-0000-000000000007", 0)
+        yield self._verifyObjectResourceCount("10000000-0000-0000-0000-000000000008", 0)
+        yield self._verifyObjectResourceCount("10000000-0000-0000-0000-000000000009", 0)
+        yield self._verifyObjectResourceCount("10000000-0000-0000-0000-000000000010", 0)
+
+        calendar = yield self.calendarUnderTest(name="calendar", home="10000000-0000-0000-0000-000000000001")
+
+        data_put_1 = """BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+PRODID:-//Example Inc.//Example Calendar//EN
+VERSION:2.0
+BEGIN:VEVENT
+DTSTAMP:20051222T205953Z
+CREATED:20060101T150000Z
+DTSTART;TZID=US/Eastern:20140101T100000
+DURATION:PT1H
+SUMMARY:event 1
+UID:event1 at ninevah.local
+ORGANIZER:MAILTO:user01 at example.com
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE:MAILTO:group01 at example.com
+ATTENDEE:MAILTO:group02 at example.com
+ATTENDEE:MAILTO:group03 at example.com
+END:VEVENT
+END:VCALENDAR"""
+
+        data_get_1 = """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//Example Inc.//Example Calendar//EN
+BEGIN:VEVENT
+UID:event1 at ninevah.local
+DTSTART;TZID=US/Eastern:20140101T100000
+DURATION:PT1H
+ATTENDEE;CN=User 01;EMAIL=user01 at example.com;RSVP=TRUE:urn:x-uid:10000000-0000-0000-0000-000000000001
+ATTENDEE;CN=Group 01;CUTYPE=GROUP;EMAIL=group01 at example.com;RSVP=TRUE;SCHEDULE-STATUS=3.7:urn:x-uid:20000000-0000-0000-0000-000000000001
+ATTENDEE;CN=Group 02;CUTYPE=GROUP;EMAIL=group02 at example.com;RSVP=TRUE;SCHEDULE-STATUS=3.7:urn:x-uid:20000000-0000-0000-0000-000000000002
+ATTENDEE;CN=Group 03;CUTYPE=GROUP;EMAIL=group03 at example.com;RSVP=TRUE;SCHEDULE-STATUS=3.7:urn:x-uid:20000000-0000-0000-0000-000000000003
+ATTENDEE;CN=User 06;EMAIL=user06 at example.com;MEMBER="urn:x-uid:20000000-0000-0000-0000-000000000002";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:10000000-0000-0000-0000-000000000006
+ATTENDEE;CN=User 07;EMAIL=user07 at example.com;MEMBER="urn:x-uid:20000000-0000-0000-0000-000000000002","urn:x-uid:20000000-0000-0000-0000-000000000003";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:10000000-0000-0000-0000-000000000007
+ATTENDEE;CN=User 08;EMAIL=user08 at example.com;MEMBER="urn:x-uid:20000000-0000-0000-0000-000000000002","urn:x-uid:20000000-0000-0000-0000-000000000003";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:10000000-0000-0000-0000-000000000008
+ATTENDEE;CN=User 09;EMAIL=user09 at example.com;MEMBER="urn:x-uid:20000000-0000-0000-0000-000000000003";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:10000000-0000-0000-0000-000000000009
+CREATED:20060101T150000Z
+ORGANIZER;CN=User 01;EMAIL=user01 at example.com:urn:x-uid:10000000-0000-0000-0000-000000000001
+SUMMARY:event 1
+END:VEVENT
+END:VCALENDAR"""
+
+        data_get_2 = """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//Example Inc.//Example Calendar//EN
+BEGIN:VEVENT
+UID:event1 at ninevah.local
+DTSTART;TZID=US/Eastern:20140101T100000
+DURATION:PT1H
+ATTENDEE;CN=User 01;EMAIL=user01 at example.com;RSVP=TRUE:urn:x-uid:10000000-0000-0000-0000-000000000001
+ATTENDEE;CN=Group 01;CUTYPE=GROUP;EMAIL=group01 at example.com;RSVP=TRUE;SCHEDULE-STATUS=3.7:urn:x-uid:20000000-0000-0000-0000-000000000001
+ATTENDEE;CN=Group 02;CUTYPE=GROUP;EMAIL=group02 at example.com;RSVP=TRUE;SCHEDULE-STATUS=3.7:urn:x-uid:20000000-0000-0000-0000-000000000002
+ATTENDEE;CN=Group 03;CUTYPE=GROUP;EMAIL=group03 at example.com;RSVP=TRUE;SCHEDULE-STATUS=3.7:urn:x-uid:20000000-0000-0000-0000-000000000003
+ATTENDEE;CN=User 07;EMAIL=user07 at example.com;MEMBER="urn:x-uid:20000000-0000-0000-0000-000000000003";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:10000000-0000-0000-0000-000000000007
+ATTENDEE;CN=User 08;EMAIL=user08 at example.com;MEMBER="urn:x-uid:20000000-0000-0000-0000-000000000003";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:10000000-0000-0000-0000-000000000008
+ATTENDEE;CN=User 09;EMAIL=user09 at example.com;MEMBER="urn:x-uid:20000000-0000-0000-0000-000000000003";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:10000000-0000-0000-0000-000000000009
+CREATED:20060101T150000Z
+ORGANIZER;CN=User 01;EMAIL=user01 at example.com:urn:x-uid:10000000-0000-0000-0000-000000000001
+SUMMARY:event 1
+END:VEVENT
+END:VCALENDAR
+"""
+
+        unpatchedRecordWithUID = DirectoryService.recordWithUID
+
+        @inlineCallbacks
+        def recordWithUID(self, uid):
+
+            if uid == "20000000-0000-0000-0000-000000000002":
+                result = None
+            else:
+                result = yield unpatchedRecordWithUID(self, uid)
+            returnValue(result)
+
+        vcalendar1 = Component.fromString(data_put_1)
+        yield calendar.createCalendarObjectWithName("data1.ics", vcalendar1)
+        yield self.commit()
+
+        cobj1 = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="10000000-0000-0000-0000-000000000001")
+        vcalendar2 = yield cobj1.component()
+        self._assertICalStrEqual(vcalendar2, data_get_1)
+
+        yield self._verifyObjectResourceCount("10000000-0000-0000-0000-000000000006", 1)
+        yield self._verifyObjectResourceCount("10000000-0000-0000-0000-000000000007", 1)
+        yield self._verifyObjectResourceCount("10000000-0000-0000-0000-000000000008", 1)
+        yield self._verifyObjectResourceCount("10000000-0000-0000-0000-000000000009", 1)
+
+        # cache group
+        groupCacher = GroupCacher(self.transactionUnderTest().directoryService())
+        wp = yield groupCacher.refreshGroup(self.transactionUnderTest(), "20000000-0000-0000-0000-000000000002")
+        yield self.commit()
+        yield wp.whenExecuted()
+
+        cobj1 = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="10000000-0000-0000-0000-000000000001")
+        vcalendar3 = yield cobj1.component()
+        self._assertICalStrEqual(vcalendar3, data_get_1)
+
+        # remove group  run cacher again
+        self.patch(DirectoryService, "recordWithUID", recordWithUID)
+
+        groupCacher = GroupCacher(self.transactionUnderTest().directoryService())
+        wp = yield groupCacher.refreshGroup(self.transactionUnderTest(), "20000000-0000-0000-0000-000000000002")
+        yield self.commit()
+        yield wp.whenExecuted()
+
+        cobj1 = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="10000000-0000-0000-0000-000000000001")
+        vcalendar4 = yield cobj1.component()
+        self._assertICalStrEqual(vcalendar4, data_get_2)
+
+        cal1 = yield self.calendarUnderTest(name="calendar", home="10000000-0000-0000-0000-000000000006")
+        cobjs = yield cal1.objectResources()
+        #FIXME: Need schema change to handle case where group comes back
+        self.assertEqual(len(cobjs), 1)
+        comp1 = yield cobjs[0].componentForUser()
+        self.assertTrue("STATUS:CANCELLED" in str(comp1))
+
+        # add group back, run cacher
+        self.patch(DirectoryService, "recordWithUID", unpatchedRecordWithUID)
+
+        groupCacher = GroupCacher(self.transactionUnderTest().directoryService())
+        wp = yield groupCacher.refreshGroup(self.transactionUnderTest(), "20000000-0000-0000-0000-000000000002")
+        self.assertNotEqual(wp, None)
+        yield self.commit()
+        yield wp.whenExecuted()
+
+        cobj1 = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="10000000-0000-0000-0000-000000000001")
+        vcalendar5 = yield cobj1.component()
+        self._assertICalStrEqual(vcalendar5, data_get_1)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140420/af856796/attachment-0001.html>


More information about the calendarserver-changes mailing list