[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