[CalendarServer-changes] [9039] CalendarServer/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Thu Apr 12 09:57:55 PDT 2012
Revision: 9039
http://trac.macosforge.org/projects/calendarserver/changeset/9039
Author: cdaboo at apple.com
Date: 2012-04-12 09:57:54 -0700 (Thu, 12 Apr 2012)
Log Message:
-----------
Calverify now set to detect and fix invalid http/https cuaddresses. Added tests and changes to support testing.
Modified Paths:
--------------
CalendarServer/trunk/calendarserver/tools/calverify.py
CalendarServer/trunk/txdav/caldav/datastore/util.py
CalendarServer/trunk/txdav/common/datastore/test/util.py
Added Paths:
-----------
CalendarServer/trunk/calendarserver/tools/test/calverify/
CalendarServer/trunk/calendarserver/tools/test/calverify/accounts.xml
CalendarServer/trunk/calendarserver/tools/test/calverify/resources.xml
CalendarServer/trunk/calendarserver/tools/test/test_calverify.py
Modified: CalendarServer/trunk/calendarserver/tools/calverify.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/calverify.py 2012-04-12 08:11:09 UTC (rev 9038)
+++ CalendarServer/trunk/calendarserver/tools/calverify.py 2012-04-12 16:57:54 UTC (rev 9039)
@@ -38,9 +38,9 @@
"""
-from calendarserver.tap.util import directoryFromConfig
from calendarserver.tools import tables
from calendarserver.tools.cmdline import utilityMain
+from calendarserver.tools.util import getDirectory
from pycalendar import definitions
from pycalendar.calendar import PyCalendar
from pycalendar.datetime import PyCalendarDateTime
@@ -56,6 +56,7 @@
from twistedcaldav.ical import Component, ignoredComponents,\
InvalidICalendarDataError
from twistedcaldav.stdconfig import DEFAULT_CONFIG_FILE
+from twistedcaldav.util import normalizationLookup
from txdav.common.datastore.sql_tables import schema, _BIND_MODE_OWN
from txdav.common.icommondatastore import InternalDataStoreError
import collections
@@ -148,6 +149,10 @@
self.reactor = reactor
self.config = config
self._directory = None
+
+ self.cuaCache = {}
+
+ self.results = {}
def startService(self):
@@ -182,14 +187,14 @@
"""
Report on home collections for which there are no directory records.
"""
- print "\n---- Finding calendar homes with no directory record ----"
+ self.output.write("\n---- Finding calendar homes with no directory record ----\n")
self.txn = self.store.newTransaction()
if self.options["verbose"]:
t = time.time()
uids = yield self.getAllHomeUIDs()
if self.options["verbose"]:
- print "getAllHomeUIDs time: %.1fs" % (time.time() - t,)
+ self.output.write("getAllHomeUIDs time: %.1fs\n" % (time.time() - t,))
missing = []
wrong_server = []
uids_len = len(uids)
@@ -197,11 +202,11 @@
for ctr, uid in enumerate(uids):
if self.options["verbose"] and divmod(ctr, uids_div)[1] == 0:
- print "%d of %d (%d%%)" % (
+ self.output.write("%d of %d (%d%%)\n" % (
ctr+1,
uids_len,
((ctr+1) * 100 / uids_len),
- )
+ ))
record = self.directoryService().recordWithGUID(uid)
if record is None:
@@ -276,7 +281,7 @@
@inlineCallbacks
def doScan(self, ical, mismatch, fix):
- print "\n---- Scanning calendar data ----"
+ self.output.write("\n---- Scanning calendar data ----\n")
self.start = PyCalendarDateTime.getToday()
self.start.setDateOnly(False)
@@ -308,8 +313,9 @@
self.txn = None
if self.options["verbose"]:
- print "%s time: %.1fs" % (descriptor, time.time() - t,)
- print "Number of events to process: %s" % (len(rows,))
+ self.output.write("%s time: %.1fs\n" % (descriptor, time.time() - t,))
+ self.output.write("Number of events to process: %s\n" % (len(rows,)))
+ self.results["Number of events to process"] = len(rows)
# Split into organizer events and attendee events
self.organized = []
@@ -325,8 +331,10 @@
self.attended.append((owner, resid, uid, md5, organizer, created, modified,))
self.attended_byuid[uid].append((owner, resid, uid, md5, organizer, created, modified,))
- print "Number of organizer events to process: %s" % (len(self.organized),)
- print "Number of attendee events to process: %s" % (len(self.attended,))
+ self.output.write("Number of organizer events to process: %s\n" % (len(self.organized),))
+ self.output.write("Number of attendee events to process: %s\n" % (len(self.attended,)))
+ self.results["Number of organizer events to process"] = len(self.organized)
+ self.results["Number of attendee events to process"] = len(self.attended)
if ical:
yield self.calendarDataCheck(rows)
@@ -448,7 +456,7 @@
Check each calendar resource for valid iCalendar data.
"""
- print "\n---- Verifying each calendar object resource ----"
+ self.output.write("\n---- Verifying each calendar object resource ----\n")
self.txn = self.store.newTransaction()
if self.options["verbose"]:
@@ -466,9 +474,9 @@
count += 1
if self.options["verbose"]:
if count == 1:
- print "Bad/Current/Total"
+ self.output.write("Bad/Current/Total\n")
if divmod(count, 100)[1] == 0:
- print "%s/%s/%s" % (badlen, count, total,)
+ self.output.write("%s/%s/%s\n" % (badlen, count, total,))
# To avoid holding locks on all the rows scanned, commit every 100 resources
if divmod(count, 100)[1] == 0:
@@ -494,13 +502,15 @@
self.output.write("\n")
self.output.write("Bad iCalendar data (total=%d):\n" % (len(results_bad),))
table.printTable(os=self.output)
+
+ self.results["Bad iCalendar data"] = results_bad
if self.options["verbose"]:
diff_time = time.time() - t
- print "Time: %.2f s Average: %.1f ms/resource" % (
+ self.output.write("Time: %.2f s Average: %.1f ms/resource\n" % (
diff_time,
(1000.0 * diff_time) / total,
- )
+ ))
errorPrefix = "Calendar data had unfixable problems:\n "
@@ -541,15 +551,33 @@
def noPrincipalPathCUAddresses(self, component, doFix):
+ def lookupFunction(cuaddr, principalFunction, config):
+
+ # Return cached results, if any.
+ if self.cuaCache.has_key(cuaddr):
+ return self.cuaCache[cuaddr]
+
+ result = normalizationLookup(cuaddr, principalFunction, config)
+
+ # Cache the result
+ self.cuaCache[cuaddr] = result
+ return result
+
for subcomponent in component.subcomponents():
if subcomponent.name() in ignoredComponents:
continue
organizer = subcomponent.getProperty("ORGANIZER")
if organizer and organizer.value().startswith("http"):
- raise InvalidICalendarDataError("iCalendar ORGANIZER starts with 'http(s)'")
+ if doFix:
+ component.normalizeCalendarUserAddresses(lookupFunction, self.directoryService().principalForCalendarUserAddress)
+ else:
+ raise InvalidICalendarDataError("iCalendar ORGANIZER starts with 'http(s)'")
for attendee in subcomponent.properties("ATTENDEE"):
if attendee.value().startswith("http"):
- raise InvalidICalendarDataError("iCalendar ATTENDEE starts with 'http(s)'")
+ if doFix:
+ component.normalizeCalendarUserAddresses(lookupFunction, self.directoryService().principalForCalendarUserAddress)
+ else:
+ raise InvalidICalendarDataError("iCalendar ATTENDEE starts with 'http(s)'")
@inlineCallbacks
def fixCalendarData(self, resid):
@@ -573,6 +601,7 @@
component.validCalendarData(doFix=True, validateRecurrences=True)
component.validCalendarForCalDAV(methodAllowed=False)
component.validOrganizerForScheduling(doFix=True)
+ self.noPrincipalPathCUAddresses(component, doFix=True)
except ValueError:
result = False
message = "Failed fix: "
@@ -594,7 +623,7 @@
view of attendee status does not match the attendee's view of their own status.
"""
- print "\n---- Verifying Organizer events against Attendee copies ----"
+ self.output.write("\n---- Verifying Organizer events against Attendee copies ----\n")
self.txn = self.store.newTransaction()
results_missing = []
@@ -607,13 +636,13 @@
for ctr, organizerEvent in enumerate(self.organized):
if self.options["verbose"] and divmod(ctr, organizer_div)[1] == 0:
- print "%d of %d (%d%%) Missing: %d Mismatched: %s" % (
+ self.output.write("%d of %d (%d%%) Missing: %d Mismatched: %s\n" % (
ctr+1,
organized_len,
((ctr+1) * 100 / organized_len),
len(results_missing),
len(results_mismatch),
- )
+ ))
# To avoid holding locks on all the rows scanned, commit every 100 resources
if divmod(ctr, 100)[1] == 0:
@@ -626,7 +655,7 @@
if calendar is None:
continue
if self.options["verbose"] and self.masterComponent(calendar) is None:
- print "Missing master for organizer: %s, resid: %s, uid: %s" % (organizer, resid, uid,)
+ self.output.write("Missing master for organizer: %s, resid: %s, uid: %s\n" % (organizer, resid, uid,))
organizerViewOfAttendees = self.buildAttendeeStates(calendar, self.start, self.end)
try:
del organizerViewOfAttendees[organizer]
@@ -667,11 +696,11 @@
results_mismatch.append((uid, resid, organizer, org_created, org_modified, organizerAttendee, att_created, att_modified))
broken = True
if self.options["details"]:
- print "Mismatch: on Organizer's side:"
- print " UID: %s" % (uid,)
- print " Organizer: %s" % (organizer,)
- print " Attendee: %s" % (organizerAttendee,)
- print " Instance: %s" % (_organizerInstance,)
+ self.output.write("Mismatch: on Organizer's side:\n")
+ self.output.write(" UID: %s\n" % (uid,))
+ self.output.write(" Organizer: %s\n" % (organizer,))
+ self.output.write(" Attendee: %s\n" % (organizerAttendee,))
+ self.output.write(" Instance: %s\n" % (_organizerInstance,))
break
# Check that the difference is only cancelled on the attendees side
for _attendeeInstance, partstat in attendeeOwnStatus.difference(organizerViewOfStatus):
@@ -680,10 +709,10 @@
results_mismatch.append((uid, resid, organizer, org_created, org_modified, organizerAttendee, att_created, att_modified))
broken = True
if self.options["details"]:
- print "Mismatch: on Attendee's side:"
- print " Organizer: %s" % (organizer,)
- print " Attendee: %s" % (organizerAttendee,)
- print " Instance: %s" % (_attendeeInstance,)
+ self.output.write("Mismatch: on Attendee's side:\n")
+ self.output.write(" Organizer: %s\n" % (organizer,))
+ self.output.write(" Attendee: %s\n" % (organizerAttendee,))
+ self.output.write(" Instance: %s\n" % (_attendeeInstance,))
break
# Check that the status for this attendee is always declined which means a missing copy of the event is OK
@@ -755,7 +784,7 @@
Make sure that for each attendee, there is a matching event for the organizer.
"""
- print "\n---- Verifying Attendee events against Organizer copies ----"
+ self.output.write("\n---- Verifying Attendee events against Organizer copies ----\n")
self.txn = self.store.newTransaction()
# Now try to match up each attendee event
@@ -767,13 +796,13 @@
for ctr, attendeeEvent in enumerate(self.attended):
if self.options["verbose"] and divmod(ctr, attended_div)[1] == 0:
- print "%d of %d (%d%%) Missing: %d Mismatched: %s" % (
+ self.output.write("%d of %d (%d%%) Missing: %d Mismatched: %s\n" % (
ctr+1,
attended_len,
((ctr+1) * 100 / attended_len),
len(missing),
len(mismatched),
- )
+ ))
# To avoid holding locks on all the rows scanned, commit every 100 resources
if divmod(ctr, 100)[1] == 0:
@@ -980,7 +1009,7 @@
configuration, creating one first if necessary.
"""
if self._directory is None:
- self._directory = directoryFromConfig(self.config)
+ self._directory = getDirectory(self.config) #directoryFromConfig(self.config)
return self._directory
@@ -1011,6 +1040,7 @@
sys.exit(1)
def makeService(store):
from twistedcaldav.config import config
+ config.TransactionTimeoutSeconds = 0
return CalVerifyService(store, options, output, reactor, config)
utilityMain(options['config'], makeService, reactor)
Added: CalendarServer/trunk/calendarserver/tools/test/calverify/accounts.xml
===================================================================
--- CalendarServer/trunk/calendarserver/tools/test/calverify/accounts.xml (rev 0)
+++ CalendarServer/trunk/calendarserver/tools/test/calverify/accounts.xml 2012-04-12 16:57:54 UTC (rev 9039)
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+Copyright (c) 2006-2010 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.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ -->
+
+<!DOCTYPE accounts SYSTEM "../../../conf/auth/accounts.dtd">
+
+<accounts realm="/Search">
+ <user>
+ <uid>example1</uid>
+ <guid>D46F3D71-04B7-43C2-A7B6-6F92F92E61D0</guid>
+ <password>example</password>
+ <name>Example User1</name>
+ <email-address>example1 at example.com</email-address>
+ </user>
+ <user>
+ <uid>example2</uid>
+ <guid>47B16BB4-DB5F-4BF6-85FE-A7DA54230F92</guid>
+ <password>example</password>
+ <name>Example User2</name>
+ <email-address>example2 at example.com</email-address>
+ </user>
+ <user>
+ <uid>example3</uid>
+ <guid>AC478592-7783-44D1-B2AE-52359B4E8415</guid>
+ <password>example</password>
+ <name>Example User3</name>
+ <email-address>example3 at example.com</email-address>
+ </user>
+</accounts>
Added: CalendarServer/trunk/calendarserver/tools/test/calverify/resources.xml
===================================================================
--- CalendarServer/trunk/calendarserver/tools/test/calverify/resources.xml (rev 0)
+++ CalendarServer/trunk/calendarserver/tools/test/calverify/resources.xml 2012-04-12 16:57:54 UTC (rev 9039)
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<accounts realm="/Search">
+</accounts>
Property changes on: CalendarServer/trunk/calendarserver/tools/test/calverify/resources.xml
___________________________________________________________________
Added: svn:executable
+ *
Added: CalendarServer/trunk/calendarserver/tools/test/test_calverify.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/test/test_calverify.py (rev 0)
+++ CalendarServer/trunk/calendarserver/tools/test/test_calverify.py 2012-04-12 16:57:54 UTC (rev 9039)
@@ -0,0 +1,357 @@
+##
+# Copyright (c) 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.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+"""
+Tests for calendarserver.tools.calverify
+"""
+
+from StringIO import StringIO
+from calendarserver.tap.util import getRootResource
+from calendarserver.tools.calverify import CalVerifyService
+from twisted.internet import reactor
+from twisted.internet.defer import inlineCallbacks
+from twisted.trial import unittest
+from twistedcaldav.config import config
+from txdav.caldav.datastore import util
+from txdav.common.datastore.test.util import buildStore, populateCalendarsFrom, CommonCommonTests
+import os
+
+
+OK_ICS = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100303T181216Z
+UID:OK
+DTEND:20000307T151500Z
+TRANSP:OPAQUE
+SUMMARY:Ancient event
+DTSTART:20000307T111500Z
+DTSTAMP:20100303T181220Z
+SEQUENCE:2
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+# Missing DTSTAMP
+BAD1_ICS = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100303T181216Z
+UID:BAD1
+DTEND:20000307T151500Z
+TRANSP:OPAQUE
+SUMMARY:Ancient event
+DTSTART:20000307T111500Z
+SEQUENCE:2
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+# Bad recurrence
+BAD2_ICS = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100303T181216Z
+UID:BAD2
+DTEND:20000307T151500Z
+TRANSP:OPAQUE
+SUMMARY:Ancient event
+DTSTART:20000307T111500Z
+DTSTAMP:20100303T181220Z
+RRULE:FREQ=DAILY;COUNT=3
+SEQUENCE:2
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20100303T181216Z
+UID:BAD2
+RECURRENCE-ID:20000307T120000Z
+DTEND:20000307T151500Z
+TRANSP:OPAQUE
+SUMMARY:Ancient event
+DTSTART:20000307T111500Z
+DTSTAMP:20100303T181220Z
+SEQUENCE:2
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+# Bad recurrence
+BAD3_ICS = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100303T181216Z
+UID:BAD2
+DTEND:20000307T151500Z
+TRANSP:OPAQUE
+SUMMARY:Ancient event
+DTSTART:20000307T111500Z
+DTSTAMP:20100303T181220Z
+RRULE:FREQ=DAILY;COUNT=3
+SEQUENCE:2
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20100303T181216Z
+UID:BAD2
+RECURRENCE-ID:20000307T120000Z
+DTEND:20000307T151500Z
+TRANSP:OPAQUE
+SUMMARY:Ancient event
+DTSTART:20000307T111500Z
+DTSTAMP:20100303T181220Z
+SEQUENCE:2
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+# Missing Organizer
+BAD3_ICS = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100303T181216Z
+UID:BAD3
+DTEND:20000307T151500Z
+TRANSP:OPAQUE
+SUMMARY:Ancient event
+DTSTART:20000307T111500Z
+DTSTAMP:20100303T181220Z
+RRULE:FREQ=DAILY;COUNT=3
+SEQUENCE:2
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20100303T181216Z
+UID:BAD3
+RECURRENCE-ID:20000307T111500Z
+DTEND:20000307T151500Z
+TRANSP:OPAQUE
+SUMMARY:Ancient event
+DTSTART:20000307T111500Z
+DTSTAMP:20100303T181220Z
+SEQUENCE:2
+ORGANIZER:mailto:example2 at example.com
+ATTENDEE:mailto:example1 at example.com
+ATTENDEE:mailto:example2 at example.com
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+# https Organizer
+BAD4_ICS = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100303T181216Z
+UID:BAD4
+DTEND:20000307T151500Z
+TRANSP:OPAQUE
+SUMMARY:Ancient event
+DTSTART:20000307T111500Z
+DTSTAMP:20100303T181220Z
+ORGANIZER:http://demo.com:8008/principals/__uids__/D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
+ATTENDEE:mailto:example1 at example.com
+ATTENDEE:mailto:example2 at example.com
+SEQUENCE:2
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+
+# https Attendee
+BAD5_ICS = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100303T181216Z
+UID:BAD5
+DTEND:20000307T151500Z
+TRANSP:OPAQUE
+SUMMARY:Ancient event
+DTSTART:20000307T111500Z
+DTSTAMP:20100303T181220Z
+ORGANIZER:mailto:example1 at example.com
+ATTENDEE:http://demo.com:8008/principals/__uids__/D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
+ATTENDEE:mailto:example2 at example.com
+SEQUENCE:2
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+
+# https Organizer and Attendee
+BAD6_ICS = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100303T181216Z
+UID:BAD6
+DTEND:20000307T151500Z
+TRANSP:OPAQUE
+SUMMARY:Ancient event
+DTSTART:20000307T111500Z
+DTSTAMP:20100303T181220Z
+ORGANIZER:http://demo.com:8008/principals/__uids__/D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
+ATTENDEE:http://demo.com:8008/principals/__uids__/D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
+ATTENDEE:mailto:example2 at example.com
+SEQUENCE:2
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+
+class CalVerifyTests(CommonCommonTests, unittest.TestCase):
+ """
+ Tests for deleting events older than a given date
+ """
+
+ metadata = {
+ "accessMode": "PUBLIC",
+ "isScheduleObject": True,
+ "scheduleTag": "abc",
+ "scheduleEtags": (),
+ "hasPrivateComment": False,
+ }
+
+ requirements = {
+ "home1" : {
+ "calendar1" : {
+ "ok.ics" : (OK_ICS, metadata,),
+ "bad1.ics" : (BAD1_ICS, metadata,),
+ "bad2.ics" : (BAD2_ICS, metadata,),
+ "bad3.ics" : (BAD3_ICS, metadata,),
+ "bad4.ics" : (BAD4_ICS, metadata,),
+ "bad5.ics" : (BAD5_ICS, metadata,),
+ "bad6.ics" : (BAD6_ICS, metadata,),
+ }
+ },
+ }
+
+ @inlineCallbacks
+ def setUp(self):
+ yield super(CalVerifyTests, self).setUp()
+ self._sqlCalendarStore = yield buildStore(self, self.notifierFactory)
+ yield self.populate()
+
+ self.patch(config.DirectoryService.params, "xmlFile",
+ os.path.join(
+ os.path.dirname(__file__), "calverify", "accounts.xml"
+ )
+ )
+ self.patch(config.ResourceService.params, "xmlFile",
+ os.path.join(
+ os.path.dirname(__file__), "calverify", "resources.xml"
+ )
+ )
+ self.rootResource = getRootResource(config, self._sqlCalendarStore)
+ self.directory = self.rootResource.getDirectory()
+
+
+ @inlineCallbacks
+ def populate(self):
+
+ # Need to bypass normal validation inside the store
+ util.validationBypass = True
+ yield populateCalendarsFrom(self.requirements, self.storeUnderTest(), migrating=True)
+ util.validationBypass = False
+ self.notifierFactory.reset()
+
+
+ def storeUnderTest(self):
+ """
+ Create and return a L{CalendarStore} for testing.
+ """
+ return self._sqlCalendarStore
+
+
+ def verifyResultsByUID(self, results, expected):
+ reported = set([(home, uid) for home, uid, _ignore_resid, _ignore_reason in results])
+ self.assertEqual(reported, expected)
+
+
+ @inlineCallbacks
+ def test_scanBadData(self):
+ """
+ CalVerifyService.doScan without fix. Make sure it detects common errors.
+ """
+
+ options = {
+ "ical":None,
+ "verbose":False,
+ "uuid":"",
+ }
+ output = StringIO()
+ calverify = CalVerifyService(self._sqlCalendarStore, options, output, reactor, config)
+ yield calverify.doScan(True, False, False)
+
+ self.assertEqual(calverify.results["Number of events to process"], 7)
+ self.verifyResultsByUID(calverify.results["Bad iCalendar data"], set((
+ ("home1", "BAD1",),
+ ("home1", "BAD2",),
+ ("home1", "BAD3",),
+ ("home1", "BAD4",),
+ ("home1", "BAD5",),
+ ("home1", "BAD6",),
+ )))
+
+
+ @inlineCallbacks
+ def test_fixBadData(self):
+ """
+ CalVerifyService.doScan without fix. Make sure it detects and fixes as much as it can.
+ """
+
+ options = {
+ "ical":None,
+ "verbose":False,
+ "uuid":"",
+ }
+ output = StringIO()
+
+ # Do fix
+ self.patch(config.Scheduling.Options, "PrincipalHostAliases", "demo.com")
+ self.patch(config, "HTTPPort", 8008)
+ calverify = CalVerifyService(self._sqlCalendarStore, options, output, reactor, config)
+ yield calverify.doScan(True, False, True)
+
+ self.assertEqual(calverify.results["Number of events to process"], 7)
+ self.verifyResultsByUID(calverify.results["Bad iCalendar data"], set((
+ ("home1", "BAD1",),
+ ("home1", "BAD2",),
+ ("home1", "BAD3",),
+ ("home1", "BAD4",),
+ ("home1", "BAD5",),
+ ("home1", "BAD6",),
+ )))
+
+ # Do scan
+ calverify = CalVerifyService(self._sqlCalendarStore, options, output, reactor, config)
+ yield calverify.doScan(True, False, False)
+
+ self.assertEqual(calverify.results["Number of events to process"], 7)
+ self.verifyResultsByUID(calverify.results["Bad iCalendar data"], set((
+ ("home1", "BAD1",),
+ )))
Modified: CalendarServer/trunk/txdav/caldav/datastore/util.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/util.py 2012-04-12 08:11:09 UTC (rev 9038)
+++ CalendarServer/trunk/txdav/caldav/datastore/util.py 2012-04-12 16:57:54 UTC (rev 9039)
@@ -44,6 +44,8 @@
log = Logger()
+validationBypass = False
+
def validateCalendarComponent(calendarObject, calendar, component, inserting, migrating):
"""
Validate a calendar component for a particular calendar.
@@ -59,6 +61,9 @@
@type component: L{VComponent}
"""
+ if validationBypass:
+ return
+
if not isinstance(component, VComponent):
raise TypeError(type(component))
Modified: CalendarServer/trunk/txdav/common/datastore/test/util.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/test/util.py 2012-04-12 08:11:09 UTC (rev 9038)
+++ CalendarServer/trunk/txdav/common/datastore/test/util.py 2012-04-12 16:57:54 UTC (rev 9039)
@@ -331,7 +331,7 @@
@inlineCallbacks
-def populateCalendarsFrom(requirements, store):
+def populateCalendarsFrom(requirements, store, migrating=False):
"""
Populate C{store} from C{requirements}.
@@ -341,6 +341,8 @@
@param store: the L{IDataStore} to populate with calendar data.
"""
populateTxn = store.newTransaction()
+ if migrating:
+ populateTxn._migrating = True
for homeUID in requirements:
calendars = requirements[homeUID]
if calendars is not None:
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120412/3f2b8b92/attachment-0001.html>
More information about the calendarserver-changes
mailing list