[CalendarServer-changes] [7460] CalendarServer/branches/users/glyph/new-export/calendarserver/tools

source_changes at macosforge.org source_changes at macosforge.org
Mon May 16 07:43:08 PDT 2011


Revision: 7460
          http://trac.macosforge.org/projects/calendarserver/changeset/7460
Author:   glyph at apple.com
Date:     2011-05-16 07:43:07 -0700 (Mon, 16 May 2011)
Log Message:
-----------
Start testing some actual export logic.

Modified Paths:
--------------
    CalendarServer/branches/users/glyph/new-export/calendarserver/tools/export.py
    CalendarServer/branches/users/glyph/new-export/calendarserver/tools/test/test_export.py

Modified: CalendarServer/branches/users/glyph/new-export/calendarserver/tools/export.py
===================================================================
--- CalendarServer/branches/users/glyph/new-export/calendarserver/tools/export.py	2011-05-16 14:42:55 UTC (rev 7459)
+++ CalendarServer/branches/users/glyph/new-export/calendarserver/tools/export.py	2011-05-16 14:43:07 UTC (rev 7460)
@@ -41,15 +41,19 @@
 from getopt import getopt, GetoptError
 from os.path import dirname, abspath
 
+from twisted.internet.defer import inlineCallbacks
+#from twisted.internet.defer import returnValue
+
 from twistedcaldav.config import ConfigurationError
-from twistedcaldav.ical import Component as iComponent, Property as iProperty
+from twistedcaldav.ical import Component, Property
 from twistedcaldav.ical import iCalendarProductID
 from twistedcaldav.resource import isCalendarCollectionResource,\
     CalendarHomeResource
 from twistedcaldav.directory.directory import DirectoryService
 
 from calendarserver.tools.util import UsageError
-from calendarserver.tools.util import loadConfig, getDirectory, dummyDirectoryRecord, autoDisableMemcached
+from calendarserver.tools.util import (
+    loadConfig, getDirectory, dummyDirectoryRecord, autoDisableMemcached)
 
 def usage(e=None):
     if e:
@@ -78,7 +82,48 @@
     else:
         sys.exit(0)
 
+
+
+def emptyComponent():
+    """
+    Create and return an empty C{VCALENDAR} component.
+    """
+    c = Component("VCALENDAR")
+    c.addProperty(Property("VERSION", "2.0"))
+    c.addProperty(Property("PRODID", iCalendarProductID))
+    return c
+
+
+
+ at inlineCallbacks
+def exportToFile(calendars, exporterUID, fileobj):
+    """
+    Export some calendars to a file as a particular UID.
+
+    @param calendars: an iterable of L{ICalendar} providers (or L{Deferred}s of
+        same).
+
+    @param exporterUID: 
+
+    @return: a L{Deferred} which fires when the export is complete.  (Note that
+        the file will not be closed.)
+    @rtype: L{Deferred} that fires with C{None}
+    """
+    comp = emptyComponent()
+    for calendar in calendars:
+        calendar = yield calendar
+        for obj in (yield calendar.calendarObjects()):
+            evt = yield obj.component()
+            for sub in evt.subcomponents():
+                comp.addComponent(sub)
+
+    fileobj.write(str(comp))
+
+
+
 def main():
+    # quiet pyflakes while I'm working on this.
+    from stopbotheringme import CalDAVFile
     try:
         (optargs, args) = getopt(
             sys.argv[1:], "hf:o:c:H:r:u:", [
@@ -173,9 +218,7 @@
                 collections.add(child)
 
     try:
-        calendar = iComponent("VCALENDAR")
-        calendar.addProperty(iProperty("VERSION", "2.0"))
-        calendar.addProperty(iProperty("PRODID", iCalendarProductID))
+        calendar = emptyComponent()
 
         uids  = set()
         tzids = set()
@@ -186,7 +229,7 @@
                 childData = child.iCalendarText()
 
                 try:
-                    childCalendar = iComponent.fromString(childData)
+                    childCalendar = Component.fromString(childData)
                 except ValueError:
                     continue
                 assert childCalendar.name() == "VCALENDAR"

Modified: CalendarServer/branches/users/glyph/new-export/calendarserver/tools/test/test_export.py
===================================================================
--- CalendarServer/branches/users/glyph/new-export/calendarserver/tools/test/test_export.py	2011-05-16 14:42:55 UTC (rev 7459)
+++ CalendarServer/branches/users/glyph/new-export/calendarserver/tools/test/test_export.py	2011-05-16 14:43:07 UTC (rev 7460)
@@ -24,8 +24,32 @@
 
 from twisted.trial.unittest import TestCase
 
-from calendarserver.tools.export import usage
+#from calendarserver.tools import export
+from twisted.internet.defer import inlineCallbacks
+from twisted.python.modules import getModule
 
+from twext.enterprise.ienterprise import AlreadyFinishedError
+
+from twistedcaldav.ical import Component
+from txdav.common.datastore.test.util import buildStore
+from txdav.common.datastore.test.util import populateCalendarsFrom
+
+from calendarserver.tools.export import usage, exportToFile, emptyComponent
+
+def holiday(uid):
+    return (
+        getModule("twistedcaldav.test").filePath
+            .sibling("data").child("Holidays").child(uid + ".ics")
+            .getContent()
+    )
+
+valentines = holiday("C31854DA-1ED0-11D9-A5E0-000A958A3252")
+newYears = holiday("C3184A66-1ED0-11D9-A5E0-000A958A3252")
+payday = (
+    getModule("twistedcaldav.test").filePath
+    .sibling("data").child("PayDay.ics").getContent()
+)
+
 class CommandLine(TestCase):
     """
     Simple tests for command-line parsing.
@@ -50,3 +74,125 @@
 
 
 
+class IntegrationTests(TestCase):
+    """
+    Tests for exporting data from a live store.
+    """
+
+    FAKE_CONFIG_FILE = 'not-a-real-config-file.plist'
+
+    @inlineCallbacks
+    def setUp(self):
+        """
+        Set up a store and fix the imported C{utilityMain} function (normally
+        from L{calendarserver.tools.cmdline.utilityMain}) to point to a
+        temporary method of this class.  Also, patch the imported C{reactor},
+        since the SUT needs to call C{reactor.stop()} in order to work with
+        L{utilityMain}.
+        """
+        self.mainCalled = False
+        #self.patch(export, "utilityMain", self.fakeUtilityMain)
+        self.store = yield buildStore(self, None)
+
+
+    def fakeUtilityMain(self, configFileName, serviceClass, reactor=None):
+        """
+        Verify a few basic things.
+        """
+        if self.mainCalled:
+            raise RuntimeError(
+                "Main called twice this test; duplicate reactor run.")
+        self.mainCalled = True
+        self.assertEquals(configFileName, self.FAKE_CONFIG_FILE)
+        theService = serviceClass(self.store)
+        theService.startService()
+
+
+    @inlineCallbacks
+    def test_emptyCalendar(self):
+        """
+        Exporting an empty calendar results in an empty calendar.
+        """
+        io = StringIO()
+        value = yield exportToFile([], "nobody", io)
+        # it doesn't return anything, it writes to the file.
+        self.assertEquals(value, None)
+        # but it should write a valid component to the file.
+        self.assertEquals(Component.fromString(io.getvalue()),
+                          emptyComponent())
+
+
+    def txn(self):
+        aTransaction = self.store.newTransaction()
+        def maybeAbort():
+            try:
+                aTransaction.abort()
+            except AlreadyFinishedError:
+                pass
+        self.addCleanup(maybeAbort)
+        return aTransaction
+
+
+    @inlineCallbacks
+    def test_oneEventCalendar(self):
+        """
+        Exporting an calendar with one event in it will result in just that
+        event.
+        """
+        yield populateCalendarsFrom(
+            {
+                "home1": {
+                    "calendar1": {
+                        "valentines-day.ics": (valentines, {})
+                    }
+                }
+            }, self.store
+        )
+
+        expected = emptyComponent()
+        [theComponent] = Component.fromString(valentines).subcomponents()
+        expected.addComponent(theComponent)
+
+        io = StringIO()
+        yield exportToFile(
+            [(yield self.txn().calendarHomeWithUID("home1"))
+              .calendarWithName("calendar1")],
+            "nobody", io
+        )
+        self.assertEquals(Component.fromString(io.getvalue()),
+                          expected)
+
+
+    @inlineCallbacks
+    def test_twoSimpleEvents(self):
+        """
+        Exporting a calendar with two events in it will result in a VCALENDAR
+        component with both VEVENTs in it.
+        """
+        yield populateCalendarsFrom(
+            {
+                "home1": {
+                    "calendar1": {
+                        "valentines-day.ics": (valentines, {}),
+                        "new-years-day.ics": (newYears, {})
+                    }
+                }
+            }, self.store
+        )
+
+        expected = emptyComponent()
+        a = Component.fromString(valentines)
+        b = Component.fromString(newYears)
+        for comp in a, b:
+            for sub in comp.subcomponents():
+                expected.addComponent(sub)
+
+        io = StringIO()
+        yield exportToFile(
+            [(yield self.txn().calendarHomeWithUID("home1"))
+              .calendarWithName("calendar1")],
+            "nobody", io
+        )
+        self.assertEquals(Component.fromString(io.getvalue()),
+                          expected)
+
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20110516/5b6ac36c/attachment-0001.html>


More information about the calendarserver-changes mailing list