[CalendarServer-changes] [10810] CalendarServer/trunk/calendarserver/tools
source_changes at macosforge.org
source_changes at macosforge.org
Tue Feb 26 07:31:16 PST 2013
Revision: 10810
http://trac.calendarserver.org//changeset/10810
Author: cdaboo at apple.com
Date: 2013-02-26 07:31:16 -0800 (Tue, 26 Feb 2013)
Log Message:
-----------
Improve double-booking detection to avoid some false positives.
Modified Paths:
--------------
CalendarServer/trunk/calendarserver/tools/calverify.py
CalendarServer/trunk/calendarserver/tools/test/test_calverify.py
Modified: CalendarServer/trunk/calendarserver/tools/calverify.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/calverify.py 2013-02-26 15:29:13 UTC (rev 10809)
+++ CalendarServer/trunk/calendarserver/tools/calverify.py 2013-02-26 15:31:16 UTC (rev 10810)
@@ -2021,15 +2021,15 @@
self.output.write("\n---- Scanning calendar data ----\n")
+ self.tzid = PyCalendarTimezone(tzid=self.options["tzid"] if self.options["tzid"] else "America/Los_Angeles")
self.now = PyCalendarDateTime.getNowUTC()
self.start = PyCalendarDateTime.getToday()
self.start.setDateOnly(False)
+ self.start.setTimezone(self.tzid)
self.end = self.start.duplicate()
self.end.offsetYear(1)
self.fix = self.options["fix"]
- self.tzid = PyCalendarTimezone(tzid=self.options["tzid"] if self.options["tzid"] else "America/Los_Angeles")
-
if self.options["verbose"] and self.options["summary"]:
ot = time.time()
@@ -2065,7 +2065,7 @@
if not record.thisServer() or not record.enabledForCalendaring:
continue
- rname = record.shortNames[0]
+ rname = record.fullName
auto = record.autoSchedule
if len(uuids) > 1 and not self.options["summary"]:
@@ -2116,14 +2116,15 @@
table.addHeader(("GUID", "Name", "Auto-Schedule", "Double-Booked",))
doubled = 0
for item in sorted(self.uuid_details):
+ if not item.doubled:
+ continue
table.addRow((
item.uuid,
item.rname,
item.auto,
item.doubled,
))
- if item.doubled:
- doubled += 1
+ doubled += 1
table.addFooter(("Total", "", "", "%d of %d" % (doubled, len(self.uuid_details),),))
self.output.write("\n")
table.printTable(os=self.output)
@@ -2171,7 +2172,7 @@
if self.options["verbose"]:
t = time.time()
- InstanceDetails = collections.namedtuple("InstanceDetails", ("resid", "uid", "start", "end",))
+ InstanceDetails = collections.namedtuple("InstanceDetails", ("resid", "uid", "start", "end", "organizer", "summary",))
end = start.duplicate()
end.offsetDay(int(self.options["days"]))
@@ -2181,6 +2182,8 @@
booked_instances = 0
details = []
rjust = 10
+ tzid = None
+ hasFloating = False
for resid in rows:
resid = resid[0]
caldata = yield self.getCalendar(resid, self.fix)
@@ -2193,7 +2196,7 @@
cal = Component(None, pycalendar=caldata)
cal = PerUserDataFilter(uuid).filter(cal)
uid = cal.resourceUID()
- instances = cal.expandTimeRanges(end, start, ignoreInvalidInstances=True)
+ instances = cal.expandTimeRanges(end, start, ignoreInvalidInstances=False)
count += 1
for instance in instances.instances.values():
@@ -2204,8 +2207,12 @@
continue
if instance.component.propertyValue("TRANSP") == "TRANSPARENT":
continue
+ dtstart = instance.component.propertyValue("DTSTART")
+ if tzid is None and dtstart.getTimezoneID():
+ tzid = PyCalendarTimezone(tzid=dtstart.getTimezoneID())
+ hasFloating |= dtstart.isDateOnly() or dtstart.floating()
- details.append(InstanceDetails(resid, uid, instance.start, instance.end,))
+ details.append(InstanceDetails(resid, uid, instance.start, instance.end, instance.component.getOrganizer(), instance.component.propertyValue("SUMMARY")))
booked_instances += 1
if self.options["verbose"] and not self.options["summary"]:
@@ -2241,13 +2248,24 @@
self.logResult("Number of instances in time-range", total_instances)
self.logResult("Number of booked instances", booked_instances)
+ # Adjust floating and sort
+ if hasFloating and tzid is not None:
+ utc = PyCalendarTimezone(utc=True)
+ for item in details:
+ if item.start.floating():
+ item.start.setTimezone(tzid)
+ item.start.adjustTimezone(utc)
+ if item.end.floating():
+ item.end.setTimezone(tzid)
+ item.end.adjustTimezone(utc)
+ details.sort(key=lambda x: x.start)
+
# Now look for double-bookings
DoubleBookedDetails = collections.namedtuple("DoubleBookedDetails", ("resid1", "uid1", "resid2", "uid2", "start",))
double_booked = []
- details.sort(key=lambda x: x.start)
current = details[0] if details else None
for next in details[1:]:
- if current.end > next.start:
+ if current.end > next.start and current.resid != next.resid and not (current.organizer == next.organizer and current.summary == next.summary):
dt = next.start.duplicate()
dt.adjustTimezone(self.tzid)
double_booked.append(DoubleBookedDetails(current.resid, current.uid, next.resid, next.uid, dt,))
Modified: CalendarServer/trunk/calendarserver/tools/test/test_calverify.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/test/test_calverify.py 2013-02-26 15:29:13 UTC (rev 10809)
+++ CalendarServer/trunk/calendarserver/tools/test/test_calverify.py 2013-02-26 15:31:16 UTC (rev 10810)
@@ -1884,7 +1884,7 @@
CREATED:20100303T181216Z
UID:INVITE_NO_OVERLAP_ICS
TRANSP:OPAQUE
-SUMMARY:Ancient event
+SUMMARY:INVITE_NO_OVERLAP_ICS
DTSTART:%(year)s0307T100000Z
DURATION:PT1H
DTSTAMP:20100303T181220Z
@@ -1905,7 +1905,7 @@
CREATED:20100303T181216Z
UID:INVITE_NO_OVERLAP1_1_ICS
TRANSP:OPAQUE
-SUMMARY:Ancient event
+SUMMARY:INVITE_NO_OVERLAP1_1_ICS
DTSTART:%(year)s0307T110000Z
DURATION:PT2H
DTSTAMP:20100303T181220Z
@@ -1925,7 +1925,7 @@
CREATED:20100303T181216Z
UID:INVITE_NO_OVERLAP1_2_ICS
TRANSP:OPAQUE
-SUMMARY:Ancient event
+SUMMARY:INVITE_NO_OVERLAP1_2_ICS
DTSTART:%(year)s0307T120000Z
DURATION:PT1H
DTSTAMP:20100303T181220Z
@@ -1946,7 +1946,7 @@
CREATED:20100303T181216Z
UID:INVITE_NO_OVERLAP2_1_ICS
TRANSP:OPAQUE
-SUMMARY:Ancient event
+SUMMARY:INVITE_NO_OVERLAP2_1_ICS
DTSTART:%(year)s0307T140000Z
DURATION:PT2H
DTSTAMP:20100303T181220Z
@@ -1965,7 +1965,7 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:INVITE_NO_OVERLAP2_2_ICS
-SUMMARY:Ancient event
+SUMMARY:INVITE_NO_OVERLAP2_2_ICS
DTSTART:%(year)s0307T150000Z
DURATION:PT1H
DTSTAMP:20100303T181220Z
@@ -2006,7 +2006,7 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:INVITE_NO_OVERLAP3_2_ICS
-SUMMARY:Ancient event
+SUMMARY:INVITE_NO_OVERLAP3_2_ICS
DTSTART:%(year)s0307T180000Z
DURATION:PT1H
DTSTAMP:20100303T181220Z
@@ -2028,7 +2028,7 @@
CREATED:20100303T181216Z
UID:INVITE_NO_OVERLAP4_1_ICS
TRANSP:OPAQUE
-SUMMARY:Ancient event
+SUMMARY:INVITE_NO_OVERLAP4_1_ICS
DTSTART:%(year)s0308T120000Z
DURATION:PT2H
DTSTAMP:20100303T181220Z
@@ -2048,7 +2048,7 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:INVITE_NO_OVERLAP4_2_ICS
-SUMMARY:Ancient event
+SUMMARY:INVITE_NO_OVERLAP4_2_ICS
DTSTART:%(year)s0309T120000Z
DURATION:PT1H
DTSTAMP:20100303T181220Z
@@ -2070,7 +2070,7 @@
CREATED:20100303T181216Z
UID:INVITE_NO_OVERLAP5_1_ICS
TRANSP:OPAQUE
-SUMMARY:Ancient event
+SUMMARY:INVITE_NO_OVERLAP5_1_ICS
DTSTART:%(year)s0312T120000Z
DURATION:PT2H
DTSTAMP:20100303T181220Z
@@ -2090,7 +2090,7 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:INVITE_NO_OVERLAP5_2_ICS
-SUMMARY:Ancient event
+SUMMARY:INVITE_NO_OVERLAP5_2_ICS
DTSTART:%(year)s0313T140000Z
DURATION:PT1H
DTSTAMP:20100303T181220Z
@@ -2103,7 +2103,7 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:INVITE_NO_OVERLAP5_2_ICS
-SUMMARY:Ancient event
+SUMMARY:INVITE_NO_OVERLAP5_2_ICS
RECURRENCE-ID:%(year)s0314T140000Z
DTSTART:%(year)s0314T130000Z
DURATION:PT1H
@@ -2116,22 +2116,126 @@
END:VCALENDAR
""".replace("\n", "\r\n") % {"year": now}
+ # Two not overlapping - one all-day
+ INVITE_NO_OVERLAP6_1_ICS = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VTIMEZONE
+TZID:America/Los_Angeles
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20071104T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
+TZNAME:PST
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+CREATED:20100303T181216Z
+UID:INVITE_NO_OVERLAP6_1_ICS
+TRANSP:OPAQUE
+SUMMARY:INVITE_NO_OVERLAP6_1_ICS
+DTSTART;TZID=America/Los_Angeles:%(year)s0320T200000
+DURATION:PT2H
+DTSTAMP:20100303T181220Z
+SEQUENCE:2
+ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
+ATTENDEE:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
+ATTENDEE:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n") % {"year": now}
+
+ INVITE_NO_OVERLAP6_2_ICS = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100303T181216Z
+UID:INVITE_NO_OVERLAP6_2_ICS
+TRANSP:OPAQUE
+SUMMARY:INVITE_NO_OVERLAP6_2_ICS
+DTSTART;VALUE=DATE:%(year)s0321
+DTSTAMP:20100303T181220Z
+SEQUENCE:2
+ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
+ATTENDEE:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
+ATTENDEE:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n") % {"year": now}
+
+ # Two overlapping - same organizer and summary
+ INVITE_NO_OVERLAP7_1_ICS = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100303T181216Z
+UID:INVITE_NO_OVERLAP7_1_ICS
+TRANSP:OPAQUE
+SUMMARY:INVITE_NO_OVERLAP7_1_ICS
+DTSTART:%(year)s0323T110000Z
+DURATION:PT2H
+DTSTAMP:20100303T181220Z
+SEQUENCE:2
+ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
+ATTENDEE:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
+ATTENDEE:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n") % {"year": now}
+
+ INVITE_NO_OVERLAP7_2_ICS = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100303T181216Z
+UID:INVITE_NO_OVERLAP7_2_ICS
+TRANSP:OPAQUE
+SUMMARY:INVITE_NO_OVERLAP7_1_ICS
+DTSTART:%(year)s0323T120000Z
+DURATION:PT1H
+DTSTAMP:20100303T181220Z
+SEQUENCE:2
+ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
+ATTENDEE:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
+ATTENDEE:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n") % {"year": now}
+
+ allEvents = {
+ "invite1.ics" : (INVITE_NO_OVERLAP_ICS, CalVerifyMismatchTestsBase.metadata,),
+ "invite2.ics" : (INVITE_NO_OVERLAP1_1_ICS, CalVerifyMismatchTestsBase.metadata,),
+ "invite3.ics" : (INVITE_NO_OVERLAP1_2_ICS, CalVerifyMismatchTestsBase.metadata,),
+ "invite4.ics" : (INVITE_NO_OVERLAP2_1_ICS, CalVerifyMismatchTestsBase.metadata,),
+ "invite5.ics" : (INVITE_NO_OVERLAP2_2_ICS, CalVerifyMismatchTestsBase.metadata,),
+ "invite6.ics" : (INVITE_NO_OVERLAP3_1_ICS, CalVerifyMismatchTestsBase.metadata,),
+ "invite7.ics" : (INVITE_NO_OVERLAP3_2_ICS, CalVerifyMismatchTestsBase.metadata,),
+ "invite8.ics" : (INVITE_NO_OVERLAP4_1_ICS, CalVerifyMismatchTestsBase.metadata,),
+ "invite9.ics" : (INVITE_NO_OVERLAP4_2_ICS, CalVerifyMismatchTestsBase.metadata,),
+ "invite10.ics" : (INVITE_NO_OVERLAP5_1_ICS, CalVerifyMismatchTestsBase.metadata,),
+ "invite11.ics" : (INVITE_NO_OVERLAP5_2_ICS, CalVerifyMismatchTestsBase.metadata,),
+ "invite12.ics" : (INVITE_NO_OVERLAP6_1_ICS, CalVerifyMismatchTestsBase.metadata,),
+ "invite13.ics" : (INVITE_NO_OVERLAP6_2_ICS, CalVerifyMismatchTestsBase.metadata,),
+ "invite14.ics" : (INVITE_NO_OVERLAP7_1_ICS, CalVerifyMismatchTestsBase.metadata,),
+ "invite15.ics" : (INVITE_NO_OVERLAP7_2_ICS, CalVerifyMismatchTestsBase.metadata,),
+ }
+
requirements = {
CalVerifyMismatchTestsBase.uuid1 : {
- "calendar" : {
- "invite1.ics" : (INVITE_NO_OVERLAP_ICS, CalVerifyMismatchTestsBase.metadata,),
- "invite2.ics" : (INVITE_NO_OVERLAP1_1_ICS, CalVerifyMismatchTestsBase.metadata,),
- "invite3.ics" : (INVITE_NO_OVERLAP1_2_ICS, CalVerifyMismatchTestsBase.metadata,),
- "invite4.ics" : (INVITE_NO_OVERLAP2_1_ICS, CalVerifyMismatchTestsBase.metadata,),
- "invite5.ics" : (INVITE_NO_OVERLAP2_2_ICS, CalVerifyMismatchTestsBase.metadata,),
- "invite6.ics" : (INVITE_NO_OVERLAP3_1_ICS, CalVerifyMismatchTestsBase.metadata,),
- "invite7.ics" : (INVITE_NO_OVERLAP3_2_ICS, CalVerifyMismatchTestsBase.metadata,),
- "invite8.ics" : (INVITE_NO_OVERLAP4_1_ICS, CalVerifyMismatchTestsBase.metadata,),
- "invite9.ics" : (INVITE_NO_OVERLAP4_2_ICS, CalVerifyMismatchTestsBase.metadata,),
- "invite10.ics" : (INVITE_NO_OVERLAP5_1_ICS, CalVerifyMismatchTestsBase.metadata,),
- "invite11.ics" : (INVITE_NO_OVERLAP5_2_ICS, CalVerifyMismatchTestsBase.metadata,),
- },
- "inbox" : {},
+ "calendar" : allEvents,
+ "inbox" : {},
},
CalVerifyMismatchTestsBase.uuid2 : {
"calendar" : {},
@@ -2142,20 +2246,8 @@
"inbox" : {},
},
CalVerifyMismatchTestsBase.uuidl1 : {
- "calendar" : {
- "invite1.ics" : (INVITE_NO_OVERLAP_ICS, CalVerifyMismatchTestsBase.metadata,),
- "invite2.ics" : (INVITE_NO_OVERLAP1_1_ICS, CalVerifyMismatchTestsBase.metadata,),
- "invite3.ics" : (INVITE_NO_OVERLAP1_2_ICS, CalVerifyMismatchTestsBase.metadata,),
- "invite4.ics" : (INVITE_NO_OVERLAP2_1_ICS, CalVerifyMismatchTestsBase.metadata,),
- "invite5.ics" : (INVITE_NO_OVERLAP2_2_ICS, CalVerifyMismatchTestsBase.metadata,),
- "invite6.ics" : (INVITE_NO_OVERLAP3_1_ICS, CalVerifyMismatchTestsBase.metadata,),
- "invite7.ics" : (INVITE_NO_OVERLAP3_2_ICS, CalVerifyMismatchTestsBase.metadata,),
- "invite8.ics" : (INVITE_NO_OVERLAP4_1_ICS, CalVerifyMismatchTestsBase.metadata,),
- "invite9.ics" : (INVITE_NO_OVERLAP4_2_ICS, CalVerifyMismatchTestsBase.metadata,),
- "invite10.ics" : (INVITE_NO_OVERLAP5_1_ICS, CalVerifyMismatchTestsBase.metadata,),
- "invite11.ics" : (INVITE_NO_OVERLAP5_2_ICS, CalVerifyMismatchTestsBase.metadata,),
- },
- "inbox" : {},
+ "calendar" : allEvents,
+ "inbox" : {},
},
}
@@ -2207,3 +2299,69 @@
sync_token_newl1 = (yield (yield self.calendarUnderTest(self.uuidl1)).syncToken())
self.assertEqual(sync_token_old1, sync_token_new1)
self.assertEqual(sync_token_oldl1, sync_token_newl1)
+
+
+ def test_instance(self):
+ """
+ CalVerifyService.doScan without fix for mismatches. Make sure it detects
+ as much as it can. Make sure sync-token is not changed.
+ """
+
+ s = """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VTIMEZONE
+TZID:America/Los_Angeles
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20071104T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
+TZNAME:PST
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:4760FF93-C7F8-4EB0-B3E8-0B22A96DB1BC
+DTSTART;TZID=America/Los_Angeles:20130221T170000
+DTEND;TZID=America/Los_Angeles:20130221T180000
+ATTENDEE;CN=Casa Blanca APPLE EMP ONLY (12) DA03 4th;CUTYPE=ROOM;PARTSTAT=
+ ACCEPTED;ROLE=REQ-PARTICIPANT:urn:uuid:366CC7BE-FEF7-4FFF-B713-6B883538A24
+ 9
+ATTENDEE;CN=Mark Chu;CUTYPE=INDIVIDUAL;EMAIL=markchu at apple.com;PARTSTAT=AC
+ CEPTED;ROLE=REQ-PARTICIPANT:urn:uuid:46F9D5D9-08E8-4987-9636-CC796F4093C6
+ATTENDEE;CN=Kristie Phan;CUTYPE=INDIVIDUAL;EMAIL=kristie_phan at apple.com;PA
+ RTSTAT=ACCEPTED:urn:uuid:97E8720F-4364-DBEC-6721-123E9A92B980
+CREATED:20130220T200530Z
+DTSTAMP:20130222T002246Z
+EXDATE:20130228T010000Z
+EXDATE:20130314T000000Z
+EXDATE:20130321T000000Z
+EXDATE:20130327T000000Z
+EXDATE:20130328T000000Z
+EXDATE:20130403T000000Z
+LOCATION:Casa Blanca APPLE EMP ONLY (12) DA03 4th
+ORGANIZER;CN=Kristie Phan;EMAIL=kristie_phan at apple.com;SCHEDULE-STATUS=1.2
+ :urn:uuid:97E8720F-4364-DBEC-6721-123E9A92B980
+RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR;WKST=SU
+SEQUENCE:13
+SUMMARY:ESD Daily Meeting
+END:VEVENT
+END:VCALENDAR
+"""
+ from twistedcaldav.ical import Component
+ c = Component.fromString(s)
+ start = PyCalendarDateTime.getToday()
+ start.setDateOnly(False)
+ end = start.duplicate()
+ end.offsetDay(30)
+ config.MaxAllowedInstances = 3000
+ i = c.expandTimeRanges(end, start, ignoreInvalidInstances=True)
+ print i
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130226/54cc0e0a/attachment-0001.html>
More information about the calendarserver-changes
mailing list