[CalendarServer-changes] [4850] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Thu Dec 10 10:59:14 PST 2009


Revision: 4850
          http://trac.macosforge.org/projects/calendarserver/changeset/4850
Author:   sagen at apple.com
Date:     2009-12-10 10:59:14 -0800 (Thu, 10 Dec 2009)
Log Message:
-----------
Adds sidecar/task test

Modified Paths:
--------------
    CalendarServer/trunk/calendarserver/sidecar/task.py
    CalendarServer/trunk/twistedcaldav/directory/test/accounts.xml
    CalendarServer/trunk/twistedcaldav/test/util.py

Added Paths:
-----------
    CalendarServer/trunk/calendarserver/sidecar/test/
    CalendarServer/trunk/calendarserver/sidecar/test/test_task.py

Modified: CalendarServer/trunk/calendarserver/sidecar/task.py
===================================================================
--- CalendarServer/trunk/calendarserver/sidecar/task.py	2009-12-10 17:28:29 UTC (rev 4849)
+++ CalendarServer/trunk/calendarserver/sidecar/task.py	2009-12-10 18:59:14 UTC (rev 4850)
@@ -25,7 +25,7 @@
 from time import sleep
 from twisted.application.service import Service, IServiceMaker
 from twisted.internet.address import IPv4Address
-from twisted.internet.defer import DeferredList, succeed
+from twisted.internet.defer import DeferredList, inlineCallbacks, returnValue
 from twisted.internet.reactor import callLater
 from twisted.plugin import IPlugin
 from twisted.python.reflect import namedClass
@@ -56,27 +56,23 @@
         self._urlsByResource = {}
         self.headers = Headers()
 
+    @inlineCallbacks
     def _getChild(self, resource, segments):
         if not segments:
             returnValue(resource)
 
-        d = resource.locateChild(self, segments)
-        d.addCallback(lambda location: self._getChild(*location))
-        return d
+        child, remaining = (yield resource.locateChild(self, segments))
+        returnValue((yield self._getChild(child, remaining)))
 
+    @inlineCallbacks
     def locateResource(self, url):
         url = url.strip("/")
         segments = url.split("/")
+        resource = (yield self._getChild(self.rootResource, segments))
+        if resource:
+            self._rememberResource(resource, url)
+        returnValue(resource)
 
-        def remember(resource):
-            if resource:
-                self._rememberResource(resource, url)
-            return resource
-
-        d = self._getChild(self.rootResource, segments)
-        d.addCallback(remember)
-        return d
-
     def _rememberResource(self, resource, url):
         self._resourcesByURL[url] = resource
         self._urlsByResource[resource] = url
@@ -91,6 +87,7 @@
     def addResponseFilter(*args, **kwds):
         pass
 
+ at inlineCallbacks
 def processInboxItem(rootResource, directory, inboxFile, inboxItemFile, uuid):
     log.debug("Processing inbox item %s" % (inboxItemFile,))
 
@@ -105,7 +102,7 @@
     try:
         method = calendar.propertyValue("METHOD")
     except ValueError:
-        return succeed(None)
+        returnValue(None)
 
     if method == "REPLY":
         # originator is attendee sending reply
@@ -118,14 +115,12 @@
     originator = LocalCalendarUser(originator, originatorPrincipal)
     recipients = (owner,)
     scheduler = DirectScheduler(FakeRequest(rootResource, "PUT"), inboxItemFile)
+    result = (yield scheduler.doSchedulingViaPUT(originator, recipients,
+        calendar, internal_request=False))
 
-    def removeItem(_):
-        if inboxItemFile.fp.exists():
-            inboxItemFile.fp.remove()
+    if os.path.exists(inboxItemFile.fp.path):
+        os.remove(inboxItemFile.fp.path)
 
-    d = scheduler.doSchedulingViaPUT(originator, recipients, calendar, internal_request=False)
-    d.addCallback(removeItem)
-    return d
 
 
 class Task(object):
@@ -135,25 +130,27 @@
         self.taskName = fileName.split(".")[0]
         self.taskFile = os.path.join(self.service.processingDir, fileName)
 
+    @inlineCallbacks
     def run(self):
-        method = getattr(self, "task_%s" % (self.taskName,), None)
-
-        if method is None:
-            log.error("Unknown task requested: %s" % (self.taskName))
+        methodName = "task_%s" % (self.taskName,)
+        method = getattr(self, methodName, None)
+        if method:
+            try:
+                log.warn("Running task '%s'" % (self.taskName))
+                yield method()
+                log.warn("Completed task '%s'" % (self.taskName))
+            except Exception, e:
+                log.error("Failed task '%s' (%s)" % (self.taskName, e))
+                os.remove(self.taskFile)
+                raise
+        else:
+            log.error("Unknown task requested: '%s'" % (self.taskName))
             os.remove(self.taskFile)
-            return succeed(None)
+            returnValue(None)
 
-        try:
-            log.warn("Running task: %s" % (self.taskName))
-            d = method()
-            d.addCallback(lambda _: log.warn("Completed task: %s" % (self.taskName)))
-            return d
-        except Exception, e:
-            log.error("Failed task '%s' (%s)" % (self.taskName, e))
-            os.remove(self.taskFile)
-            raise
-
+    @inlineCallbacks
     def task_scheduleinboxes(self):
+
         calendars = self.service.root.getChild("calendars")
         uidDir = calendars.getChild("__uids__")
 
@@ -177,25 +174,21 @@
 
             inboxItemFile = inboxFile.getChild(fileName)
 
-            def processed(_):
-                inboxItems.remove(inboxItem)
-
-                # Rewrite the task file in case we exit before we're done
-                with open(self.taskFile + ".tmp", "w") as output:
-                    for inboxItem in inboxItems:
-                        output.write("%s\n" % (inboxItem,))
-                os.rename(self.taskFile + ".tmp", self.taskFile)
-
-            d = processInboxItem(
+            yield processInboxItem(
                 self.service.root,
                 self.service.directory,
                 inboxFile,
                 inboxItemFile,
                 uuid
             )
-            d.addCallback(processed)
-            return d
+            inboxItems.remove(inboxItem)
 
+            # Rewrite the task file in case we exit before we're done
+            with open(self.taskFile + ".tmp", "w") as output:
+                for inboxItem in inboxItems:
+                    output.write("%s\n" % (inboxItem,))
+            os.rename(self.taskFile + ".tmp", self.taskFile)
+
         os.remove(self.taskFile)
 
 

Added: CalendarServer/trunk/calendarserver/sidecar/test/test_task.py
===================================================================
--- CalendarServer/trunk/calendarserver/sidecar/test/test_task.py	                        (rev 0)
+++ CalendarServer/trunk/calendarserver/sidecar/test/test_task.py	2009-12-10 18:59:14 UTC (rev 4850)
@@ -0,0 +1,216 @@
+##
+# Copyright (c) 2009 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.
+##
+
+import os, zlib
+
+from calendarserver.sidecar.task import CalDAVTaskServiceMaker, CalDAVTaskOptions, Task
+from os.path import dirname, abspath
+from twext.python.plistlib import writePlist
+from twisted.python.usage import Options, UsageError
+from twistedcaldav.config import config, ConfigDict, _mergeData
+from twistedcaldav.stdconfig import DEFAULT_CONFIG, DEFAULT_CONFIG_FILE
+from twistedcaldav.test.util import TestCase
+from twisted.internet.defer import inlineCallbacks
+
+import memcacheclient
+
+# Points to top of source tree.
+sourceRoot = dirname(dirname(dirname(dirname(abspath(__file__)))))
+
+
+class CalDAVTaskServiceTest(TestCase):
+    """
+    Test various parameters of our usage.Options subclass
+    """
+    def setUp(self):
+        """
+        Set up our options object, giving it a parent, and forcing the
+        global config to be loaded from defaults.
+        """
+        TestCase.setUp(self)
+        self.options = CalDAVTaskOptions()
+        self.options.parent = Options()
+        self.options.parent["uid"] = 0
+        self.options.parent["gid"] = 0
+        self.options.parent["nodaemon"] = False
+
+        self.config = ConfigDict(DEFAULT_CONFIG)
+
+        accountsFile = os.path.join(sourceRoot, "twistedcaldav/directory/test/accounts.xml")
+        self.config["DirectoryService"] = {
+            "params": {"xmlFile": accountsFile},
+            "type": "twistedcaldav.directory.xmlfile.XMLDirectoryService"
+        }
+
+        self.config.DocumentRoot   = self.mktemp()
+        self.config.DataRoot       = self.mktemp()
+        self.config.ProcessType    = "Single"
+        self.config.Memcached.ClientEnabled = False
+        self.config.Memcached.ServerEnabled = False
+
+
+        pemFile = os.path.join(sourceRoot, "twistedcaldav/test/data/server.pem")
+        self.config.SSLPrivateKey = pemFile
+        self.config.SSLCertificate = pemFile
+
+        os.mkdir(self.config.DocumentRoot)
+        os.mkdir(self.config.DataRoot)
+
+        self.configFile = self.mktemp()
+
+        self.writeConfig()
+
+    def writeConfig(self):
+        """
+        Flush self.config out to self.configFile
+        """
+        writePlist(self.config, self.configFile)
+
+    def tearDown(self):
+        config.setDefaults(DEFAULT_CONFIG)
+        config.reload()
+
+    def makeService(self):
+        self.options.parseOptions(["-f", self.configFile])
+        return CalDAVTaskServiceMaker().makeService(self.options)
+
+    @inlineCallbacks
+    def test_taskService(self):
+        service = self.makeService()
+
+        structure = {
+            "calendars" : {
+                "__uids__" : {
+                    "64" : {
+                        "23" : {
+                            "6423F94A-6B76-4A3A-815B-D52CFD77935D" : {
+                                "calendar": {
+                                    "@xattrs" :
+                                    {
+                                        "WebDAV:{DAV:}resourcetype" : zlib.compress("<?xml version='1.0' encoding='UTF-8'?>\r\n<resourcetype xmlns='DAV:'>\r\n<collection/>\r\n<calendar xmlns='urn:ietf:params:xml:ns:caldav'/>\r\n</resourcetype>\r\n"),
+                                    },
+                                },
+                                "inbox": {
+                                    "unprocessed.ics": {
+                                        "@contents" : unprocessed,
+                                    }
+                                },
+                            }
+                        }
+                    }
+                }
+            },
+        }
+
+        self.createHierarchy(structure, root=self.config.DocumentRoot)
+
+        structure = {
+            "tasks" : {
+                "incoming" : { },
+                "processing" : {
+                    "scheduleinboxes.task" : {
+                        "@contents" : os.path.join(
+                            self.config.DocumentRoot,
+                            "calendars",
+                            "__uids__",
+                            "64",
+                            "23",
+                            "6423F94A-6B76-4A3A-815B-D52CFD77935D",
+                            "inbox",
+                            "unprocessed.ics"
+                        ),
+                    },
+                },
+            },
+        }
+
+        self.createHierarchy(structure, root=self.config.DataRoot)
+
+        task = Task(service, "scheduleinboxes.task")
+        yield task.run()
+
+        # Aftwards we want to see a .ics file in calendar and inbox
+        structure = {
+            "calendars" : {
+                "__uids__" : {
+                    "64" : {
+                        "23" : {
+                            "6423F94A-6B76-4A3A-815B-D52CFD77935D" : {
+                                "calendar": {
+                                    ".db.sqlite" : {
+                                        "@contents" : None,
+                                    },
+                                    "*.ics": {
+                                        "@contents" : None,
+                                    },
+                                },
+                                "inbox": {
+                                    ".db.sqlite" : {
+                                        "@contents" : None,
+                                    },
+                                    "*.ics": {
+                                        "@contents" : None,
+                                    },
+                                },
+                            }
+                        }
+                    }
+                }
+            },
+        }
+        self.assertTrue(self.verifyHierarchy(self.config.DocumentRoot, structure))
+
+unprocessed = """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:REQUEST
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+BEGIN:VTIMEZONE
+TZID:US/Pacific
+BEGIN:STANDARD
+DTSTART:20071104T020000
+RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+TZNAME:PST
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:A40F4892-B40F-4C0F-B8D0-F4EB2C97F4B9
+DTSTART;TZID=US/Pacific:20091209T120000
+DTEND;TZID=US/Pacific:20091209T130000
+ATTENDEE;CN=Wilfredo Sanchez;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=N
+ EEDS-ACTION;EMAIL=wsanchez at example.com;RSVP=TRUE:/principals/__uids__/6423F94
+ A-6B76-4A3A-815B-D52CFD77935D/
+ATTENDEE;CUTYPE=INDIVIDUAL;CN=Morgen Sagen;PARTSTAT=ACCEPTED:mailto:sagen at exam
+ ple.com
+CREATED:20091209T183541Z
+DTSTAMP:20091209T183612Z
+ORGANIZER;CN=Morgen Sagen:mailto:sagen at example.com
+SEQUENCE:6
+SUMMARY:Test
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+

Modified: CalendarServer/trunk/twistedcaldav/directory/test/accounts.xml
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/test/accounts.xml	2009-12-10 17:28:29 UTC (rev 4849)
+++ CalendarServer/trunk/twistedcaldav/directory/test/accounts.xml	2009-12-10 18:59:14 UTC (rev 4850)
@@ -54,6 +54,13 @@
     <email-address>dreid at example.com</email-address>
   </user>
   <user>
+    <uid>sagen</uid>
+    <guid>34360DAD-9BDE-4508-3C34-250394720345</guid>
+    <password>negas</password>
+    <name>Morgen Sagen</name>
+    <email-address>sagen at example.com</email-address>
+  </user>
+  <user>
     <uid>nocalendar</uid>
     <guid>543D28BA-F74F-4D5F-9243-B3E3A61171E5</guid>
     <password>radnelacon</password>

Modified: CalendarServer/trunk/twistedcaldav/test/util.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/util.py	2009-12-10 17:28:29 UTC (rev 4849)
+++ CalendarServer/trunk/twistedcaldav/test/util.py	2009-12-10 18:59:14 UTC (rev 4850)
@@ -45,9 +45,10 @@
         config.Memcached.ServerEnabled = False
         memcacheclient.ClientFactory.allowTestCache = True
 
-    def createHierarchy(self, structure):
-        root = self.mktemp()
-        os.mkdir(root)
+    def createHierarchy(self, structure, root=None):
+        if root is None:
+            root = self.mktemp()
+            os.mkdir(root)
 
         def createChildren(parent, subStructure):
             for childName, childStructure in subStructure.iteritems():
@@ -88,6 +89,18 @@
                 if childName in actual:
                     actual.remove(childName)
 
+                if childName.startswith("*"):
+                    ext = childName.split(".")[1]
+                    found = False
+                    for actualFile in actual:
+                        if actualFile.endswith(ext):
+                            actual.remove(actualFile)
+                            found = True
+                            break
+                    if found:
+                        continue
+                    
+
                 childPath = os.path.join(parent, childName)
 
                 if not os.path.exists(childPath):
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20091210/2becbd48/attachment-0001.html>


More information about the calendarserver-changes mailing list