[CalendarServer-changes] [8607] CalendarServer/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Mon Jan 30 18:27:52 PST 2012
Revision: 8607
http://trac.macosforge.org/projects/calendarserver/changeset/8607
Author: cdaboo at apple.com
Date: 2012-01-30 18:27:52 -0800 (Mon, 30 Jan 2012)
Log Message:
-----------
Fix handling of the case where a "fake master" event exists in ics data with only yhr organizer's
attendee property present. For migration we fix those events on the way in. Otherwise we now
ignore the problem on PUT implicit scheduling. Calverify can also fix existing data in that state.
Modified Paths:
--------------
CalendarServer/trunk/twistedcaldav/ical.py
CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py
CalendarServer/trunk/twistedcaldav/scheduling/test/test_icaldiff.py
CalendarServer/trunk/twistedcaldav/test/test_icalendar.py
CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py
Added Paths:
-----------
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_bad/calendar_fix_recurrence/3.ics
Modified: CalendarServer/trunk/twistedcaldav/ical.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/ical.py 2012-01-30 02:08:49 UTC (rev 8606)
+++ CalendarServer/trunk/twistedcaldav/ical.py 2012-01-31 02:27:52 UTC (rev 8607)
@@ -1,6 +1,6 @@
# -*- test-case-name: twistedcaldav.test.test_icalendar -*-
##
-# Copyright (c) 2005-2011 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2012 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -1333,15 +1333,19 @@
if None in all_rids:
all_rids.remove(None)
- # Get the set of all valid recurrence IDs
- valid_rids = self.validInstances(all_rids, ignoreInvalidInstances=True)
+ # If the master has no recurrence properties treat any other components as invalid
+ if master.isRecurring():
+ # Get the set of all valid recurrence IDs
+ valid_rids = self.validInstances(all_rids, ignoreInvalidInstances=True)
+
+ # Get the set of all RDATEs and add those to the valid set
+ rdates = []
+ for property in master.properties("RDATE"):
+ rdates.extend([_rdate.getValue() for _rdate in property.value()])
+ valid_rids.update(set(rdates))
+ else:
+ valid_rids = set()
- # Get the set of all RDATEs and add those to the valid set
- rdates = []
- for property in master.properties("RDATE"):
- rdates.extend([_rdate.getValue() for _rdate in property.value()])
- valid_rids.update(set(rdates))
-
# Determine the invalid recurrence IDs by set subtraction
invalid_rids = all_rids - valid_rids
Modified: CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py 2012-01-30 02:08:49 UTC (rev 8606)
+++ CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py 2012-01-31 02:27:52 UTC (rev 8607)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2005-2009 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2012 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -254,8 +254,8 @@
except (ValueError, TypeError), ex:
log.err("Cannot truncate calendar resource: %s" % (ex,))
- self.newCalendar = self.oldcalendar.duplicate()
- self.newMaster = self.newCalendar.masterComponent()
+ returnCalendar = self.oldcalendar.duplicate()
+ returnMaster = returnCalendar.masterComponent()
changeCausesReply = False
changedRids = []
@@ -330,7 +330,7 @@
# Attendee may decline by EXDATE'ing an instance - we need to handle that
if exdatesnew is None or rid in exdatesnew:
# Mark Attendee as DECLINED in the server instance
- if self._attendeeDecline(self.newCalendar.overriddenComponent(rid)):
+ if self._attendeeDecline(returnCalendar.overriddenComponent(rid)):
changeCausesReply = True
changedRids.append(rid.getText() if rid else "")
else:
@@ -344,12 +344,12 @@
self._logDiffError("attendeeMerge: Missing EXDATE for cancelled components from first calendar: %s" % (key,))
else:
# Remove the CANCELLED component from the new calendar and add an EXDATE
- overridden = self.newCalendar.overriddenComponent(rid)
- self.newCalendar.removeComponent(overridden)
- if self.newMaster:
+ overridden = returnCalendar.overriddenComponent(rid)
+ returnCalendar.removeComponent(overridden)
+ if returnMaster:
# Use the original R-ID value so we preserve the timezone
original_rid = component.propertyValue("RECURRENCE-ID")
- self.newMaster.addProperty(Property("EXDATE", [original_rid,]))
+ returnMaster.addProperty(Property("EXDATE", [original_rid,]))
# Derive a new component in the new calendar for each new one in setnew
for key in setnew - setold:
@@ -366,40 +366,40 @@
setnew.remove(key)
else:
# Derive new component with STATUS:CANCELLED and remove EXDATE
- newOverride = self.newCalendar.deriveInstance(rid, allowCancelled=True)
+ newOverride = returnCalendar.deriveInstance(rid, allowCancelled=True)
if newOverride is None:
# We used to generate a 403 here - but instead we now ignore this error and let the server data
# override the client
self._logDiffError("attendeeMerge: Could not derive instance for cancelled component: %s" % (key,))
setnew.remove(key)
else:
- self.newCalendar.addComponent(newOverride)
+ returnCalendar.addComponent(newOverride)
else:
# Derive new component
- newOverride = self.newCalendar.deriveInstance(rid)
+ newOverride = returnCalendar.deriveInstance(rid)
if newOverride is None:
# We used to generate a 403 here - but instead we now ignore this error and let the server data
# override the client
self._logDiffError("attendeeMerge: Could not derive instance for uncancelled component: %s" % (key,))
setnew.remove(key)
else:
- self.newCalendar.addComponent(newOverride)
+ returnCalendar.addComponent(newOverride)
- # So now newCalendar has all the same components as set2. Check changes and do transfers.
+ # So now returnCalendar has all the same components as set2. Check changes and do transfers.
# Make sure the same VCALENDAR properties match
- if not self._checkVCALENDARProperties(self.newCalendar, self.newcalendar):
+ if not self._checkVCALENDARProperties(returnCalendar, self.newcalendar):
# We used to generate a 403 here - but instead we now ignore this error and let the server data
# override the client
self._logDiffError("attendeeMerge: VCALENDAR properties do not match")
# Now we transfer per-Attendee
- # data from newcalendar into newCalendar to sync up changes, whilst verifying that other
+ # data from newcalendar into returnCalendar to sync up changes, whilst verifying that other
# key properties are unchanged
declines = []
for key in setnew:
_ignore_name, _ignore_uid, rid = key
- serverData = self.newCalendar.overriddenComponent(rid)
+ serverData = returnCalendar.overriddenComponent(rid)
clientData = mapnew[key]
allowed, reply = self._transferAttendeeData(serverData, clientData, declines)
@@ -414,11 +414,11 @@
# We need to derive instances for any declined using an EXDATE
for decline in sorted(declines):
- overridden = self.newCalendar.overriddenComponent(decline)
+ overridden = returnCalendar.overriddenComponent(decline)
if not overridden:
- overridden = self.newCalendar.deriveInstance(decline)
+ overridden = returnCalendar.deriveInstance(decline)
if overridden:
- self.newCalendar.addComponent(overridden)
+ returnCalendar.addComponent(overridden)
if self._attendeeDecline(overridden):
changeCausesReply = True
changedRids.append(decline.getText() if decline else "")
@@ -426,7 +426,7 @@
self._logDiffError("attendeeMerge: Unable to override an instance to mark as DECLINED: %s" % (decline,))
return False, False, (), None
- return True, changeCausesReply, changedRids, self.newCalendar
+ return True, changeCausesReply, changedRids, returnCalendar
def _checkVCALENDARProperties(self, serverData, clientData):
@@ -459,6 +459,12 @@
# ATTENDEE/PARTSTAT/RSVP
serverAttendee = serverComponent.getAttendeeProperty((self.attendee,))
clientAttendee = clientComponent.getAttendeeProperty((self.attendee,))
+
+ # Possible case where one ATTENDEE prop is missing - this happens with a "fake" master sometimes
+ if serverAttendee is None or clientAttendee is None:
+ log.err("ATTENDEE for user making an attendee change is missing: %s" % (self.attendee,))
+ return False, False
+
if serverAttendee.parameterValue("PARTSTAT", "NEEDS-ACTION") != clientAttendee.parameterValue("PARTSTAT", "NEEDS-ACTION"):
serverAttendee.setParameter("PARTSTAT", clientAttendee.parameterValue("PARTSTAT", "NEEDS-ACTION"))
replyNeeded = True
@@ -632,6 +638,12 @@
@return: C{bool} indicating whether the PARTSTAT value was in fact changed
"""
attendee = component.getAttendeeProperty((self.attendee,))
+
+ # Possible case where ATTENDEE prop is missing - this happens with a "fake" master sometimes
+ if attendee is None:
+ log.err("ATTENDEE for user making an attendee change is missing: %s" % (self.attendee,))
+ return False
+
partstatChanged = attendee.parameterValue("PARTSTAT", "NEEDS-ACTION") != "DECLINED"
attendee.setParameter("PARTSTAT", "DECLINED")
prop = component.getProperty("X-APPLE-NEEDS-REPLY")
Modified: CalendarServer/trunk/twistedcaldav/scheduling/test/test_icaldiff.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/test/test_icaldiff.py 2012-01-30 02:08:49 UTC (rev 8606)
+++ CalendarServer/trunk/twistedcaldav/scheduling/test/test_icaldiff.py 2012-01-31 02:27:52 UTC (rev 8607)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2005-2009 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2012 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -3000,6 +3000,210 @@
"mailto:user2 at example.com",
(False, False, (), None,)
),
+ (
+ "#3.1 Single overridden component, fake master, missing attendee",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+RECURRENCE-ID:20080601T120000Z
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:user2 at example.com
+END:VEVENT
+END:VCALENDAR
+""",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080601T120000Z
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2 at example.com
+END:VEVENT
+END:VCALENDAR
+""",
+ "mailto:user2 at example.com",
+ (True, True, ('20080601T120000Z',), """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080601T120000Z
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+END:VEVENT
+END:VCALENDAR
+""",)
+ ),
+ (
+ "#3.2 Single overridden component, fake master, missing attendee in old",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+RECURRENCE-ID:20080601T120000Z
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:user2 at example.com
+END:VEVENT
+END:VCALENDAR
+""",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2 at example.com
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080601T120000Z
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2 at example.com
+END:VEVENT
+END:VCALENDAR
+""",
+ "mailto:user2 at example.com",
+ (True, True, ('20080601T120000Z',), """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080601T120000Z
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+END:VEVENT
+END:VCALENDAR
+""",)
+ ),
+ (
+ "#3.3 Single overridden component, fake master, missing attendee in new",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:user2 at example.com
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+RECURRENCE-ID:20080601T120000Z
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:user2 at example.com
+END:VEVENT
+END:VCALENDAR
+""",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080601T120000Z
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2 at example.com
+END:VEVENT
+END:VCALENDAR
+""",
+ "mailto:user2 at example.com",
+ (True, True, ('20080601T120000Z',), """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080601T120000Z
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+END:VEVENT
+END:VCALENDAR
+""",)
+ ),
)
for description, calendar1, calendar2, attendee, result in data:
Modified: CalendarServer/trunk/twistedcaldav/test/test_icalendar.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_icalendar.py 2012-01-30 02:08:49 UTC (rev 8606)
+++ CalendarServer/trunk/twistedcaldav/test/test_icalendar.py 2012-01-31 02:27:52 UTC (rev 8607)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2005-2009 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2012 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -4062,6 +4062,28 @@
(PyCalendarDateTime(2007, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), False),
)
),
+ (
+ "1.12 - fake master OK",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DTSTAMP:20080601T120000Z
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20071114T000000Z
+DTSTART:20071114T000000Z
+DTSTAMP:20080601T120000Z
+END:VEVENT
+END:VCALENDAR
+""",
+ (
+ (PyCalendarDateTime(2007, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), False),
+ )
+ ),
)
for clear_cache in (True, False):
@@ -4078,6 +4100,55 @@
actual_results = ical.validInstances(rids)
self.assertEqual(actual_results, expected_results, "Failed comparison: %s %s" % (title, actual_results,))
+ def test_valid_recurrence_ids(self):
+
+ data = (
+ (
+ "1.1 - fake master",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DTSTAMP:20080601T120000Z
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20071114T000000Z
+DTSTART:20071114T000000Z
+DTSTAMP:20080601T120000Z
+END:VEVENT
+END:VCALENDAR
+""",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DTSTAMP:20080601T120000Z
+RDATE:20071114T000000Z
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20071114T000000Z
+DTSTART:20071114T000000Z
+DTSTAMP:20080601T120000Z
+END:VEVENT
+END:VCALENDAR
+""",
+ 1, 0,
+ ),
+ )
+
+ for title, calendar, result_calendar, result_fixed, result_unfixed in data:
+ ical = Component.fromString(calendar)
+ fixed, unfixed = ical.validRecurrenceIDs(doFix=True)
+ self.assertEqual(str(ical), result_calendar.replace("\n", "\r\n"), "Failed comparison: %s %s" % (title, str(ical),))
+ self.assertEqual(len(fixed), result_fixed, "Failed fixed comparison: %s %s" % (title, fixed,))
+ self.assertEqual(len(unfixed), result_unfixed, "Failed unfixed: %s %s" % (title, unfixed,))
+
def test_mismatched_until(self):
invalid = (
"""BEGIN:VCALENDAR
Added: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_bad/calendar_fix_recurrence/3.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_bad/calendar_fix_recurrence/3.ics (rev 0)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_bad/calendar_fix_recurrence/3.ics 2012-01-31 02:27:52 UTC (rev 8607)
@@ -0,0 +1,42 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VTIMEZONE
+TZID:US/Eastern
+LAST-MODIFIED:20040110T032845Z
+BEGIN:STANDARD
+DTSTART:20001026T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:20000404T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:uid4
+DTSTART;TZID=US/Eastern:20060104T160000
+DURATION:PT1H
+CREATED:20060102T190000Z
+DESCRIPTION:Some notes
+DTSTAMP:20051222T210507Z
+SUMMARY:event 6-%ctr changed again
+END:VEVENT
+BEGIN:VEVENT
+UID:uid4
+RECURRENCE-ID;TZID=US/Eastern:20060104T160000
+DTSTART;TZID=US/Eastern:20060104T160000
+DURATION:PT1H
+CREATED:20060102T190000Z
+DESCRIPTION:Some notes
+DTSTAMP:20051222T210507Z
+SUMMARY:event 6-%ctr changed again
+END:VEVENT
+END:VCALENDAR
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py 2012-01-30 02:08:49 UTC (rev 8606)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py 2012-01-31 02:27:52 UTC (rev 8607)
@@ -189,7 +189,7 @@
toCalendar = yield toHome.calendarWithName("calendar")
ok, bad = (yield _migrateCalendar(fromCalendar, toCalendar,
lambda x: x.component()))
- self.assertEqual(ok, 2)
+ self.assertEqual(ok, 3)
self.assertEqual(bad, 0)
self.transactionUnderTest().commit()
@@ -302,6 +302,53 @@
END:VCALENDAR
""".replace("\n", "\r\n"))
+ toResource = yield toCalendar.calendarObjectWithName("3.ics")
+ caldata = yield toResource.component()
+ self.assertEqual(str(caldata), """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VTIMEZONE
+TZID:US/Eastern
+LAST-MODIFIED:20040110T032845Z
+BEGIN:DAYLIGHT
+DTSTART:20000404T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20001026T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:uid4
+DTSTART;TZID=US/Eastern:20060104T160000
+DURATION:PT1H
+CREATED:20060102T190000Z
+DESCRIPTION:Some notes
+DTSTAMP:20051222T210507Z
+RDATE;TZID=US/Eastern:20060104T160000
+SUMMARY:event 6-%ctr changed again
+END:VEVENT
+BEGIN:VEVENT
+UID:uid4
+RECURRENCE-ID;TZID=US/Eastern:20060104T160000
+DTSTART;TZID=US/Eastern:20060104T160000
+DURATION:PT1H
+CREATED:20060102T190000Z
+DESCRIPTION:Some notes
+DTSTAMP:20051222T210507Z
+SUMMARY:event 6-%ctr changed again
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n"))
+
@inlineCallbacks
def test_migrateDuplicateAttachmentsCalendarFromFile(self):
"""
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120130/a092815e/attachment-0001.html>
More information about the calendarserver-changes
mailing list