[CalendarServer-changes] [784]
CalendarServer/trunk/twistedcaldav/directory
source_changes at macosforge.org
source_changes at macosforge.org
Fri Dec 8 22:30:19 PST 2006
Revision: 784
http://trac.macosforge.org/projects/calendarserver/changeset/784
Author: wsanchez at apple.com
Date: 2006-12-08 22:30:19 -0800 (Fri, 08 Dec 2006)
Log Message:
-----------
Add AggregateDirectoryService
Modified Paths:
--------------
CalendarServer/trunk/twistedcaldav/directory/test/util.py
Added Paths:
-----------
CalendarServer/trunk/twistedcaldav/directory/aggregate.py
CalendarServer/trunk/twistedcaldav/directory/test/test_aggregate.py
Added: CalendarServer/trunk/twistedcaldav/directory/aggregate.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/aggregate.py (rev 0)
+++ CalendarServer/trunk/twistedcaldav/directory/aggregate.py 2006-12-09 06:30:19 UTC (rev 784)
@@ -0,0 +1,111 @@
+##
+# Copyright (c) 2006 Apple Computer, 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.
+#
+# DRI: Wilfredo Sanchez, wsanchez at apple.com
+##
+
+"""
+Directory service implementation which aggregates multiple directory
+services.
+"""
+
+__all__ = [
+ "AggregateDirectoryService",
+ "DuplicateRecordTypeError",
+]
+
+from twistedcaldav.directory.idirectory import IDirectoryService
+from twistedcaldav.directory.directory import DirectoryService, DirectoryRecord, DirectoryError
+from twistedcaldav.directory.directory import UnknownRecordTypeError
+
+import twistedcaldav.directory.test.util
+
+class AggregateDirectoryService(DirectoryService):
+ """
+ L{IDirectoryService} implementation which aggregates multiple directory services.
+ """
+ baseGUID = "06FB225F-39E7-4D34-B1D1-29925F5E619B"
+
+ def __init__(self, services):
+ DirectoryService.__init__(self)
+
+ realmName = None
+ recordTypes = {}
+
+ for service in services:
+ service = IDirectoryService(service)
+
+ if service.realmName != realmName:
+ assert realmName is None, (
+ "Aggregated directory services must have the same realm name: %r != %r"
+ % (service.realmName, realmName)
+ )
+ realmName = service.realmName
+
+ if not hasattr(service, "recordTypePrefix"):
+ service.recordTypePrefix = ""
+ prefix = service.recordTypePrefix
+
+ for recordType in (prefix + r for r in service.recordTypes()):
+ if recordType in recordTypes:
+ raise DuplicateRecordTypeError(
+ "%r is in multiple services: %s, %s"
+ % (recordType, recordTypes[recordType], service)
+ )
+ recordTypes[recordType] = service
+
+ self.realmName = realmName
+ self._recordTypes = recordTypes
+
+ def recordTypes(self):
+ return set(self._recordTypes)
+
+ def listRecords(self, recordType):
+ return self._query("listRecords", recordType)
+
+ def recordWithShortName(self, recordType, shortName):
+ return self._query("recordWithShortName", recordType, shortName)
+
+ def recordWithGUID(self, guid):
+ return self._queryAll("recordWithGUID", address)
+
+ def recordWithCalendarUserAddress(self, address):
+ return self._queryAll("recordWithCalendarUserAddress", address)
+
+ def serviceForRecordType(self, recordType):
+ try:
+ return self._recordTypes[recordType]
+ except KeyError:
+ raise UnknownRecordTypeError(recordType)
+
+ def _query(self, query, recordType, *args):
+ service = self.serviceForRecordType(recordType)
+ return getattr(service, query)(
+ recordType[len(service.recordTypePrefix):],
+ *[a[len(service.recordTypePrefix):] for a in args]
+ )
+
+ def _queryAll(self, query, *args):
+ for service in self._recordTypes.values():
+ record = getattr(service, query)(*args)
+ if record is not None:
+ return record
+ else:
+ return None
+
+class DuplicateRecordTypeError(DirectoryError):
+ """
+ Duplicate record type.
+ """
Added: CalendarServer/trunk/twistedcaldav/directory/test/test_aggregate.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/test/test_aggregate.py (rev 0)
+++ CalendarServer/trunk/twistedcaldav/directory/test/test_aggregate.py 2006-12-09 06:30:19 UTC (rev 784)
@@ -0,0 +1,77 @@
+##
+# Copyright (c) 2005-2006 Apple Computer, 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.
+#
+# DRI: Wilfredo Sanchez, wsanchez at apple.com
+##
+
+from itertools import chain
+
+from twistedcaldav.directory.apache import BasicDirectoryService
+from twistedcaldav.directory.xmlfile import XMLDirectoryService
+from twistedcaldav.directory.aggregate import AggregateDirectoryService
+
+from twistedcaldav.directory.test.test_apache import digestRealm, basicUserFile, groupFile
+from twistedcaldav.directory.test.test_xmlfile import xmlFile
+
+import twistedcaldav.directory.test.util
+
+apache_prefix = "apache:"
+xml_prefix = "xml:"
+
+testServices = (
+ (apache_prefix, twistedcaldav.directory.test.test_apache.Apache ),
+ (xml_prefix , twistedcaldav.directory.test.test_xmlfile.XMLFile),
+)
+
+class AggregatedDirectories (twistedcaldav.directory.test.util.DirectoryTestCase):
+ def _recordTypes(self):
+ recordTypes = set()
+ for prefix, testClass in testServices:
+ for recordType in testClass.recordTypes:
+ recordTypes.add(prefix + recordType)
+ return recordTypes
+
+ def _records(key):
+ def get(self):
+ records = {}
+ for prefix, testClass in testServices:
+ for record, info in getattr(testClass, key).iteritems():
+ info = dict(info)
+ info["prefix"] = prefix
+ info["members"] = tuple(
+ (t, prefix + s) for t, s in info.get("members", {})
+ )
+ records[prefix + record] = info
+ return records
+ return get
+
+ recordTypes = property(_recordTypes)
+ users = property(_records("users"))
+ groups = property(_records("groups"))
+ resources = property(_records("resources"))
+
+ recordTypePrefixes = tuple(s[0] for s in testServices)
+
+ def service(self):
+ """
+ Returns an IDirectoryService.
+ """
+ apacheService = BasicDirectoryService(digestRealm, basicUserFile, groupFile)
+ apacheService.recordTypePrefix = apache_prefix
+
+ xmlService = XMLDirectoryService(xmlFile)
+ xmlService.recordTypePrefix = xml_prefix
+
+ return AggregateDirectoryService((apacheService, xmlService))
Modified: CalendarServer/trunk/twistedcaldav/directory/test/util.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/test/util.py 2006-12-09 03:49:36 UTC (rev 783)
+++ CalendarServer/trunk/twistedcaldav/directory/test/util.py 2006-12-09 06:30:19 UTC (rev 784)
@@ -23,6 +23,8 @@
from twisted.cred.credentials import UsernamePassword
from twisted.web2.auth.digest import DigestedCredentials, calcResponse, calcHA1
+from twistedcaldav.directory.directory import UnknownRecordTypeError
+
# FIXME: Add tests for GUID hooey, once we figure out what that means here
class DirectoryTestCase (twisted.trial.unittest.TestCase):
@@ -48,6 +50,9 @@
"""
raise NotImplementedError("Subclass needs to implement service()")
+ # For aggregator subclasses
+ recordTypePrefixes = ("",)
+
def test_realm(self):
"""
IDirectoryService.realm
@@ -90,44 +95,31 @@
self.assertEquals(self.recordNames("resource"), set(self.resources.keys()))
- def test_recordWithShortName_user(self):
+ def test_recordWithShortName(self):
"""
- IDirectoryService.recordWithShortName("user")
+ IDirectoryService.recordWithShortName()
"""
- if not self.users:
- raise SkipTest("No users")
+ for recordType, data in (
+ ( "user" , self.users ),
+ ( "group" , self.groups ),
+ ( "resource", self.resources ),
+ ):
+ if not data:
+ raise SkipTest("No %s" % (recordType,))
- service = self.service()
- for shortName in self.users:
- record = service.recordWithShortName("user", shortName)
- self.compare(record, shortName, self.users[shortName])
- self.assertEquals(service.recordWithShortName("user", "IDunnoWhoThisIsIReallyDont"), None)
+ service = self.service()
+ for shortName, info in data.iteritems():
+ record = service.recordWithShortName(info.get("prefix", "") + recordType, shortName)
+ self.failUnless(record, "No record (%s)%s" % (info.get("prefix", "") + recordType, shortName))
+ self.compare(record, shortName, data[shortName])
- def test_recordWithShortName_group(self):
- """
- IDirectoryService.recordWithShortName("group")
- """
- if not self.groups:
- raise SkipTest("No groups")
+ for prefix in self.recordTypePrefixes:
+ try:
+ record = service.recordWithShortName(prefix + recordType, "IDunnoWhoThisIsIReallyDont")
+ except UnknownRecordTypeError:
+ continue
+ self.assertEquals(record, None)
- service = self.service()
- for shortName in self.groups:
- record = service.recordWithShortName("group", shortName)
- self.compare(record, shortName, self.groups[shortName])
- self.assertEquals(service.recordWithShortName("group", "IDunnoWhoThisIsIReallyDont"), None)
-
- def test_recordWithShortName_resource(self):
- """
- XMLDirectoryService.recordWithShortName("resource")
- """
- if not self.resources:
- raise SkipTest("No resources")
-
- service = self.service()
- for shortName in self.resources:
- record = service.recordWithShortName("resource", shortName)
- self.compare(record, shortName, self.resources[shortName])
-
def test_recordWithGUID(self):
service = self.service()
record = None
@@ -161,9 +153,10 @@
raise SkipTest("No groups")
service = self.service()
- for group in self.groups:
- groupRecord = service.recordWithShortName("group", group)
- result = set((m.recordType, m.shortName) for m in groupRecord.members())
+ for group, info in self.groups.iteritems():
+ prefix = info.get("prefix", "")
+ groupRecord = service.recordWithShortName(prefix + "group", group)
+ result = set((m.recordType, prefix + m.shortName) for m in groupRecord.members())
expected = set(self.groups[group]["members"])
self.assertEquals(
result, expected,
@@ -184,9 +177,10 @@
( "group", self.groups ),
):
service = self.service()
- for shortName in data:
- record = service.recordWithShortName(recordType, shortName)
- result = set(g.shortName for g in record.groups())
+ for shortName, info in data.iteritems():
+ prefix = info.get("prefix", "")
+ record = service.recordWithShortName(prefix + recordType, shortName)
+ result = set(prefix + g.shortName for g in record.groups())
expected = set(g for g in self.groups if (record.recordType, shortName) in self.groups[g]["members"])
self.assertEquals(
result, expected,
@@ -194,8 +188,18 @@
)
def recordNames(self, recordType):
- return set(r.shortName for r in self.service().listRecords(recordType))
+ service = self.service()
+ names = set()
+ for prefix in self.recordTypePrefixes:
+ try:
+ records = service.listRecords(prefix + recordType)
+ except UnknownRecordTypeError:
+ continue
+ for record in records:
+ names.add(prefix + record.shortName)
+ return names
+
def allEntries(self):
for data, recordType in (
(self.users, "user" ),
@@ -219,7 +223,12 @@
addresses = set(value("addresses"))
addresses.add("urn:uuid:%s" % (record.guid,))
- self.assertEquals(record.shortName, shortName)
+ if hasattr(record.service, "recordTypePrefix"):
+ prefix = record.service.recordTypePrefix
+ else:
+ prefix = ""
+
+ self.assertEquals(prefix + record.shortName, shortName)
self.assertEquals(set(record.calendarUserAddresses), addresses)
if value("guid"):
@@ -228,6 +237,13 @@
if value("name"):
self.assertEquals(record.fullName, value("name"))
+ def servicePrefix(self):
+ service = self.service()
+ if hasattr(service, "recordTypePrefix"):
+ return service.recordTypePrefix
+ else:
+ return ""
+
class BasicTestCase (DirectoryTestCase):
"""
Tests a directory implementation with basic auth.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20061208/fb9ad9b0/attachment.html
More information about the calendarserver-changes
mailing list