[CalendarServer-changes] [2141] CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav /directory

source_changes at macosforge.org source_changes at macosforge.org
Wed Feb 13 15:32:57 PST 2008


Revision: 2141
          http://trac.macosforge.org/projects/calendarserver/changeset/2141
Author:   wsanchez at apple.com
Date:     2008-02-13 15:32:53 -0800 (Wed, 13 Feb 2008)

Log Message:
-----------
Merge http://svn.macosforge.org/repository/calendarserver/CalendarServer/branches/users/wsanchez/cache-miss

Modified Paths:
--------------
    CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav/directory/appleopendirectory.py
    CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav/directory/idirectory.py
    CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav/directory/principal.py
    CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav/directory/test/test_opendirectory.py
    CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav/directory/test/test_opendirectoryrecords.py
    CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav/directory/test/test_opendirectoryschema.py

Modified: CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav/directory/appleopendirectory.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav/directory/appleopendirectory.py	2008-02-13 23:19:36 UTC (rev 2140)
+++ CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav/directory/appleopendirectory.py	2008-02-13 23:32:53 UTC (rev 2141)
@@ -45,8 +45,8 @@
 
 from plistlib import readPlistFromString, readPlist
 
-_serverPreferences = '/Library/Preferences/com.apple.servermgr_info.plist'
-_saclGroup = 'com.apple.access_calendar'
+serverPreferences = '/Library/Preferences/com.apple.servermgr_info.plist'
+saclGroup = 'com.apple.access_calendar'
 
 recordListCacheTimeout = 60 * 30 # 30 minutes
 
@@ -93,12 +93,10 @@
                     logging.err("Unable to locate virtual host record: %s" % (e,), system="OpenDirectoryService")
                     raise
 
-                if os.path.exists(_serverPreferences):
-                    serverInfo = readPlist(_serverPreferences)
+                if os.path.exists(serverPreferences):
+                    serverInfo = readPlist(serverPreferences)
 
-                    self.isWorkgroupServer = serverInfo.get(
-                        'ServiceConfig', {}).get(
-                        'IsWorkgroupServer', False)
+                    self.isWorkgroupServer = serverInfo.get('ServiceConfig', {}).get('IsWorkgroupServer', False)
 
                     if self.isWorkgroupServer:
                         logging.info("Enabling Workgroup Server compatibility mode", system="OpenDirectoryService")
@@ -133,11 +131,14 @@
                 dsattributes.eDSExact,
                 False,
                 dsattributes.kDSStdRecordTypeGroups,
-                [dsattributes.kDSNAttrGroupMembers,
-                 dsattributes.kDSNAttrNestedGroups])
+                [dsattributes.kDSNAttrGroupMembers, dsattributes.kDSNAttrNestedGroups]
+            )
 
             if not result:
-                logging.err("Couldn't find group %s when trying to expand nested groups." % (groupGUID,), system="OpenDirectoryService")
+                logging.err(
+                    "Couldn't find group %s when trying to expand nested groups."
+                    % (groupGUID,), system="OpenDirectoryService"
+                )
                 continue
 
             group = result[0][1]
@@ -206,7 +207,7 @@
         if len(records) == 0:
             raise OpenDirectoryInitError(
                 "Open Directory (node=%s) has no /Computers records with a virtual hostname: %s"
-                % (self.realmName, vhostname,)
+                % (self.realmName, vhostname)
             )
 
         # Now find all appropriate records and determine the enabled (only) service tags for each.
@@ -230,14 +231,14 @@
             raise OpenDirectoryInitError(
                 "Open Directory (node=%s) no /Computers records with an enabled and valid "
                 "calendar service were found matching virtual hostname: %s"
-                % (self.realmName, vhostname,)
+                % (self.realmName, vhostname)
             )
 
     def _parseServiceInfo(self, vhostname, recordname, record):
 
         # Extract some useful attributes
         recordguid = record[dsattributes.kDS1AttrGeneratedUID]
-        recordlocation = "%s/Computers/%s" % (record[dsattributes.kDSNAttrMetaNodeLocation], recordname,)
+        recordlocation = "%s/Computers/%s" % (record[dsattributes.kDSNAttrMetaNodeLocation], recordname)
 
         # First check for apple-serviceinfo attribute
         plist = record.get('dsAttrTypeNative:apple-serviceinfo', None)
@@ -251,7 +252,7 @@
             logging.err(
                 "Open Directory (node=%s) %s record does not have a "
                 "com.apple.macosxserver.virtualhosts in its apple-serviceinfo attribute value"
-                % (self.realmName, recordlocation,), system="OpenDirectoryService"
+                % (self.realmName, recordlocation), system="OpenDirectoryService"
             )
             return False
         
@@ -310,14 +311,14 @@
         # Create the string we will use to match users with accounts on this server
         servicetag = "%s:%s:calendar" % (recordguid, hostguid)
         
-        self.computerRecords[recordlocation] = (recordname, enabled, servicetag,)
+        self.computerRecords[recordlocation] = (recordname, enabled, servicetag)
         
         if enabled:
             self.servicetags.add(servicetag)
         
         return True
     
-    def _getCalendarUserAddresses(self, recordType, recordName, record):
+    def _calendarUserAddresses(self, recordType, recordName, record):
         """
         Extract specific attributes from the directory record for use as calendar user address.
         
@@ -325,7 +326,6 @@
         @param record: a C{dict} containing the attributes retrieved from the directory.
         @return: a C{set} of C{str} for each expanded calendar user address.
         """
-        
         # Now get the addresses
         result = set()
         
@@ -350,9 +350,9 @@
         plist = readPlistFromString(plist)
         wpframework = plist.get("com.apple.WhitePagesFramework", {})
         autoaccept = wpframework.get("AutoAcceptsInvitation", False)
-        proxy= wpframework.get("CalendaringDelegate")
+        proxy = wpframework.get("CalendaringDelegate")
         
-        return (autoaccept, proxy,)
+        return (autoaccept, proxy)
 
     def recordTypes(self):
         return (
@@ -374,8 +374,10 @@
 
                 def onError(f):
                     storage["status"] = "stale" # Keep trying
-                    logging.err("Unable to load records of type %s from OpenDirectory due to unexpected error: %s"
-                            % (recordType, f), system="OpenDirectoryService")
+                    logging.err(
+                        "Unable to load records of type %s from OpenDirectory due to unexpected error: %s"
+                        % (recordType, f), system="OpenDirectoryService"
+                    )
 
                 d = deferToThread(self.reloadCache, recordType)
                 d.addErrback(onError)
@@ -400,55 +402,87 @@
         except KeyError:
             # Cache miss; try looking the record up, in case it is new
             # FIXME: This is a blocking call (hopefully it's a fast one)
-            self.reloadCache(recordType, shortName)
+            self.reloadCache(recordType, shortName=shortName)
             return self.recordsForType(recordType).get(shortName, None)
 
     def recordWithGUID(self, guid):
-        # Override super's implementation with something faster.
-        for recordType in self.recordTypes():
-            record = self._storage(recordType)["guids"].get(guid, None)
-            if record:
-                return record
-        else:
-            return None
+        def lookup():
+            for recordType in self.recordTypes():
+                record = self._storage(recordType)["guids"].get(guid, None)
+                if record:
+                    return record
+            else:
+                return None
 
-    def reloadCache(self, recordType, shortName=None):
-        
+        record = lookup()
+
+        if record is None:
+            # Cache miss; try looking the record up, in case it is new
+            for recordType in self.recordTypes():
+                self.reloadCache(recordType, guid=guid)
+                record = lookup()
+                if record is not None:
+                    logging.info("Faulted record with GUID %s into %s record cache" % (guid, recordType), system="OpenDirectoryService")
+                    break
+            else:
+                logging.info("Unable to find any record with GUID %s" % (guid,), system="OpenDirectoryService")
+
+        return record
+
+    def reloadCache(self, recordType, shortName=None, guid=None):
         if shortName:
-            logging.info("Trying to add record %s to %s record cache" % (shortName, recordType,), system="OpenDirectoryService")
-        else:
+            logging.info("Faulting record %s into %s record cache" % (shortName, recordType), system="OpenDirectoryService")
+        elif guid is None:
             logging.info("Reloading %s record cache" % (recordType,), system="OpenDirectoryService")
 
-        results = self._queryDirectory(recordType, shortName)
+        results = self._queryDirectory(recordType, shortName=shortName, guid=guid)
         
-        records  = {}
-        guids    = {}
-        disabled_names = set()
-        disabled_guids = set()
+        if shortName is None and guid is None:
+            records = {}
+            guids   = {}
 
-        for (key, value) in results:
+            disabledNames = set()
+            disabledGUIDs = set()
+        else:
+            storage = self._records[recordType]
+
+            records = storage["records"]
+            guids   = storage["guids"]
+
+            disabledNames = storage["disabled names"]
+            disabledGUIDs = storage["disabled guids"]
+
+        for (recordShortName, value) in results:
             enabledForCalendaring = True
 
             if self.requireComputerRecord:
                 if not value.get(dsattributes.kDSNAttrServicesLocator):
                     if recordType == DirectoryService.recordType_groups:
                         enabledForCalendaring = False
-                        logging.debug("Group %s is not enabled for calendaring but may be used in ACLs" % (key,), system="OpenDirectoryService")
+                        logging.debug(
+                            "Group %s is not enabled for calendaring but may be used in ACLs"
+                            % (recordShortName,), system="OpenDirectoryService"
+                        )
                     else:
-                        logging.err("Directory (incorrectly) returned a record with no ServicesLocator attribute: %s" % (key,), system="OpenDirectoryService")
+                        logging.err(
+                            "Directory (incorrectly) returned a record with no ServicesLocator attribute: %s"
+                            % (recordShortName,), system="OpenDirectoryService"
+                        )
                         continue
 
             # Now get useful record info.
-            recordShortName = key
-            guid = value.get(dsattributes.kDS1AttrGeneratedUID)
-            if not guid:
+            recordGUID     = value.get(dsattributes.kDS1AttrGeneratedUID)
+            recordFullName = value.get(dsattributes.kDS1AttrDistinguishedName)
+            recordNodeName = value.get(dsattributes.kDSNAttrMetaNodeLocation)
+
+            if not recordGUID:
+                logging.debug("Record (%s)%s in node %s has no GUID; ignoring." % (recordType, recordShortName, recordNodeName),
+                              system="OpenDirectoryService")
                 continue
-            realName = value.get(dsattributes.kDS1AttrDistinguishedName)
-            nodename = value.get(dsattributes.kDSNAttrMetaNodeLocation)
 
             # Get calendar user addresses from directory record.
             if enabledForCalendaring:
-                calendarUserAddresses = self._getCalendarUserAddresses(recordType, key, value)
+                calendarUserAddresses = self._calendarUserAddresses(recordType, recordShortName, value)
             else:
                 calendarUserAddresses = ()
 
@@ -480,53 +514,56 @@
             record = OpenDirectoryRecord(
                 service               = self,
                 recordType            = recordType,
-                guid                  = guid,
-                nodename              = nodename,
+                guid                  = recordGUID,
+                nodeName              = recordNodeName,
                 shortName             = recordShortName,
-                fullName              = realName,
+                fullName              = recordFullName,
                 calendarUserAddresses = calendarUserAddresses,
                 autoSchedule          = autoSchedule,
                 enabledForCalendaring = enabledForCalendaring,
                 memberGUIDs           = memberGUIDs,
                 proxyGUIDs            = proxyGUIDs,
             )
-            
+
+            del recordShortName
+            del recordGUID
+
+            def disableRecord(record):
+                logging.warn("Record disabled due to conflict: %s" % (record,), system="OpenDirectoryService")
+
+                shortName = record.shortName
+                guid      = record.guid
+
+                disabledNames.add(shortName)
+                disabledGUIDs.add(guid)
+
+                if shortName in records:
+                    del records[shortName]
+                if guid in guids:
+                    del guids[guid]
+
             # Check for disabled items
-            if recordShortName in disabled_names or guid in disabled_guids:
-                disabled_names.add(recordShortName)
-                disabled_guids.add(guid)
-                logging.warn("Record disabled: %s, with GUID: %s" % (recordShortName, guid,), system="OpenDirectoryService")
+            if record.shortName in disabledNames or record.guid in disabledGUIDs:
+                disableRecord(record)
             else:
                 # Check for duplicate items and disable all names/guids for mismatched duplicates.
-                ok_to_add = True
-                if recordShortName in records:
-                    existing_record = records[recordShortName]
-                    if existing_record.guid != guid:
-                        disabled_names.add(recordShortName)
-                        disabled_guids.add(guid)
-                        disabled_guids.add(existing_record.guid)
-                        del records[existing_record.shortName]
-                        del guids[existing_record.guid]
-                        logging.warn("Record disabled: %s, with GUID: %s" % (existing_record.shortName, existing_record.guid,), system="OpenDirectoryService")
-                        logging.warn("Record disabled: %s, with GUID: %s" % (recordShortName, guid,), system="OpenDirectoryService")
-                        ok_to_add = False
-                elif guid in guids:
-                    existing_record = guids[guid]
-                    if existing_record.shortName != recordShortName:
-                        disabled_names.add(recordShortName)
-                        disabled_guids.add(guid)
-                        disabled_names.add(existing_record.shortName)
-                        del records[existing_record.shortName]
-                        del guids[existing_record.guid]
-                        logging.warn("Record disabled: %s, with GUID: %s" % (existing_record.shortName, existing_record.guid,), system="OpenDirectoryService")
-                        logging.warn("Record disabled: %s, with GUID: %s" % (recordShortName, guid,), system="OpenDirectoryService")
-                        ok_to_add = False
-                
-                if ok_to_add:
-                    records[recordShortName] = guids[guid] = record
-                    logging.debug("Populated record: %s, with GUID: %s" % (records[recordShortName], guid,), system="OpenDirectoryService")
+                if record.shortName in records:
+                    existing_record = records[record.shortName]
+                elif record.guid in guids:
+                    existing_record = guids[record.guid]
+                else:
+                    existing_record = None
 
-        if shortName is None:
+                if existing_record is not None:
+                    if record.guid != existing_record.guid or record.shortName != existing_record.shortName:
+                        disableRecord(existing_record)
+                        disableRecord(record)
+
+                if record.shortName not in disabledNames:
+                    records[record.shortName] = guids[record.guid] = record
+                    logging.debug("Added record %s to OD record cache" % (record,), system="OpenDirectoryService")
+
+        if shortName is None and guid is None:
             #
             # Replace the entire cache
             #
@@ -534,8 +571,8 @@
                 "status"        : "new",
                 "records"       : records,
                 "guids"         : guids,
-                "disabled_names": disabled_names,
-                "disabled_guids": disabled_guids,
+                "disabled names": disabledNames,
+                "disabled guids": disabledGUIDs,
             }
 
             def rot():
@@ -551,37 +588,9 @@
 
             self._records[recordType] = storage
 
-        elif records:
-            #
-            # Update one record, if found
-            #
-            assert len(records) == 1, "shortName = %r, records = %r" % (shortName, len(records))
-            
-            # Need to check that this record has not been disabled
-            storage = self._records[recordType]
-            if shortName in storage["disabled_names"] or record.guid in storage["disabled_guids"]:
-                storage["disabled_guids"].add(record.guid)
-                storage["disabled_names"].add(shortName)
-                logging.warn("Record disabled: %s, with GUID: %s" % (shortName, record.guid,), system="OpenDirectoryService")
-                records = {}
-            elif record.guid in storage["guids"]:
-                # Got a duplicate GUID - for now we disable the record  being looked up. On the next cache refresh
-                # the existing record will also get disabled.
-                storage["disabled_guids"].add(record.guid)
-                storage["disabled_names"].add(shortName)
-                logging.warn("Record disabled: %s, with GUID: %s" % (shortName, record.guid,), system="OpenDirectoryService")
-                records = {}
-            else:
-                storage["records"][shortName] = record
-                storage["guids"][record.guid] = record
+            logging.debug("Added %d records to %s OD record cache" % (len(self._records[recordType]["guids"]), recordType), system="OpenDirectoryService")
 
-        if shortName:
-            logging.info("Added %d records for %s in %s record cache" % (len(records), shortName, recordType,), system="OpenDirectoryService")
-        else:
-            logging.info("Found %d records for %s record cache" % (len(self._records[recordType]["guids"]), recordType,), system="OpenDirectoryService")
-
-    def _queryDirectory(self, recordType, shortName=None):
-
+    def _queryDirectory(self, recordType, shortName=None, guid=None):
         attrs = [
             dsattributes.kDS1AttrGeneratedUID,
             dsattributes.kDS1AttrDistinguishedName,
@@ -608,46 +617,40 @@
             attrs.append(dsattributes.kDSNAttrResourceInfo)
         
         else:
-            raise UnknownRecordTypeError("Unknown Open Directory record type: %s"
-                                         % (recordType,))
+            raise UnknownRecordTypeError("Unknown Open Directory record type: %s" % (recordType))
 
         if self.requireComputerRecord:
             if self.isWorkgroupServer and recordType == DirectoryService.recordType_users:
-                if shortName is None:
+                if shortName is None and guid is None:
                     results = opendirectory.queryRecordsWithAttribute_list(
                         self.directory,
                         dsattributes.kDSNAttrRecordName,
-                        _saclGroup,
+                        saclGroup,
                         dsattributes.eDSExact,
                         False,
                         dsattributes.kDSStdRecordTypeGroups,
-                        [dsattributes.kDSNAttrGroupMembers,
-                         dsattributes.kDSNAttrNestedGroups])
+                        [dsattributes.kDSNAttrGroupMembers, dsattributes.kDSNAttrNestedGroups]
+                    )
 
                     if len(results) == 1:
-                        members = results[0][1].get(
-                            dsattributes.kDSNAttrGroupMembers, [])
-    
-                        nestedGroups = results[0][1].get(
-                            dsattributes.kDSNAttrNestedGroups, [])
+                        members      = results[0][1].get(dsattributes.kDSNAttrGroupMembers, [])
+                        nestedGroups = results[0][1].get(dsattributes.kDSNAttrNestedGroups, [])
                     else:
                         members = []
                         nestedGroups = []
 
                     guidQueries = []
 
-                    for GUID in self._expandGroupMembership(members,
-                                                            nestedGroups):
+                    for GUID in self._expandGroupMembership(members, nestedGroups):
                         guidQueries.append(
-                            dsquery.match(dsattributes.kDS1AttrGeneratedUID,
-                                          GUID, dsattributes.eDSExact))
+                            dsquery.match(dsattributes.kDS1AttrGeneratedUID, GUID, dsattributes.eDSExact)
+                        )
 
                     if not guidQueries:
                         logging.warn("No SACL enabled users found.", system="OpenDirectoryService")
                         return ()
 
-                    query = dsquery.expression(dsquery.expression.OR,
-                                               guidQueries)
+                    query = dsquery.expression(dsquery.expression.OR, guidQueries)
 
             #
             # For groups, we'll load all entries, even if they don't
@@ -655,12 +658,15 @@
             #
             elif recordType != DirectoryService.recordType_groups:
                 tag_queries = []
+
                 for tag in self.servicetags:
                     tag_queries.append(dsquery.match(dsattributes.kDSNAttrServicesLocator, tag, dsattributes.eDSExact))
+
                 if len(tag_queries) == 1:
                     subquery = tag_queries[0]
                 else:
                     subquery = dsquery.expression(dsquery.expression.OR, tag_queries)
+
                 if query is None:
                     query = subquery
                 else:
@@ -668,12 +674,17 @@
 
         if shortName is not None:
             subquery = dsquery.match(dsattributes.kDSNAttrRecordName, shortName, dsattributes.eDSExact)
+        elif guid is not None:
+            subquery = dsquery.match(dsattributes.kDS1AttrGeneratedUID, guid, dsattributes.eDSExact)
+        else:
+            subquery = None
+
+        if subquery is not None:
             if query is None:
                 query = subquery
             else:
                 query = dsquery.expression(dsquery.expression.AND, (subquery, query))
 
-
         try:
             if query:
                 if isinstance(query, dsquery.match):
@@ -711,7 +722,7 @@
     Open Directory implementation of L{IDirectoryRecord}.
     """
     def __init__(
-        self, service, recordType, guid, nodename, shortName, fullName,
+        self, service, recordType, guid, nodeName, shortName, fullName,
         calendarUserAddresses, autoSchedule, enabledForCalendaring,
         memberGUIDs, proxyGUIDs,
     ):
@@ -725,10 +736,26 @@
             autoSchedule          = autoSchedule,
             enabledForCalendaring = enabledForCalendaring,
         )
-        self._nodename = nodename
+        self.nodeName = nodeName
         self._memberGUIDs = tuple(memberGUIDs)
         self._proxyGUIDs = tuple(proxyGUIDs)
 
+    def __repr__(self):
+        if self.service.realmName == self.nodeName:
+            location = self.nodeName
+        else:
+            location = "%s->%s" % (self.service.realmName, self.nodeName)
+
+        return "<%s[%s@%s(%s)] %s(%s) %r>" % (
+            self.__class__.__name__,
+            self.recordType,
+            self.service.guid,
+            location,
+            self.guid,
+            self.shortName,
+            self.fullName
+        )
+
     def members(self):
         if self.recordType != DirectoryService.recordType_groups:
             return
@@ -756,9 +783,9 @@
 
     def proxyFor(self):
         for proxyRecord in itertools.chain(
-                                  self.service.recordsForType(DirectoryService.recordType_resources).itervalues(),
-                                  self.service.recordsForType(DirectoryService.recordType_locations).itervalues()
-                              ):
+            self.service.recordsForType(DirectoryService.recordType_resources).itervalues(),
+            self.service.recordsForType(DirectoryService.recordType_locations).itervalues(),
+        ):
             if self.guid in proxyRecord._proxyGUIDs:
                 yield proxyRecord
 
@@ -773,16 +800,14 @@
 
             # Check with directory services
             try:
-                if opendirectory.authenticateUserBasic(self.service.directory, self._nodename, self.shortName, credentials.password):
+                if opendirectory.authenticateUserBasic(self.service.directory, self.nodeName, self.shortName, credentials.password):
                     # Cache the password to avoid future DS queries
                     self.password = credentials.password
                     return True
             except opendirectory.ODError, e:
                 logging.err("Open Directory (node=%s) error while performing basic authentication for user %s: %s"
                             % (self.service.realmName, self.shortName, e), system="OpenDirectoryService")
-
-            return False
-
+                return False
         elif isinstance(credentials, DigestedCredentials):
             try:
                 # We need a special format for the "challenge" and "response" strings passed into open directory, as it is
@@ -790,15 +815,21 @@
                 
                 try:
                     challenge = 'Digest realm="%(realm)s", nonce="%(nonce)s", algorithm=%(algorithm)s' % credentials.fields
-                    response = ('Digest username="%(username)s", '
-                                'realm="%(realm)s", '
-                                'nonce="%(nonce)s", '
-                                'uri="%(uri)s", '
-                                'response="%(response)s",'
-                                'algorithm=%(algorithm)s') % credentials.fields
+                    response = (
+                        'Digest username="%(username)s", '
+                        'realm="%(realm)s", '
+                        'nonce="%(nonce)s", '
+                        'uri="%(uri)s", '
+                        'response="%(response)s",'
+                        'algorithm=%(algorithm)s'
+                    ) % credentials.fields
                 except KeyError, e:
-                    logging.err("Open Directory (node=%s) error while performing digest authentication for user %s: missing digest response field: %s in: %s"
-                            % (self.service.realmName, self.shortName, e, credentials.fields), system="OpenDirectoryService")
+                    logging.err(
+                        "Open Directory (node=%s) error while performing digest authentication for user %s: "
+                        "missing digest response field: %s in: %s"
+                        % (self.service.realmName, self.shortName, e, credentials.fields),
+                        system="OpenDirectoryService"
+                    )
                     return False
 
                 if self.digestcache[credentials.fields["uri"]] == response:
@@ -809,7 +840,7 @@
             try:
                 if opendirectory.authenticateUserDigest(
                     self.service.directory,
-                    self._nodename,
+                    self.nodeName,
                     self.shortName,
                     challenge,
                     response,
@@ -824,8 +855,10 @@
 
                     return True
             except opendirectory.ODError, e:
-                logging.err("Open Directory (node=%s) error while performing digest authentication for user %s: %s"
-                        % (self.service.realmName, self.shortName, e), system="OpenDirectoryService")
+                logging.err(
+                    "Open Directory (node=%s) error while performing digest authentication for user %s: %s"
+                    % (self.service.realmName, self.shortName, e), system="OpenDirectoryService"
+                )
                 return False
 
         return super(OpenDirectoryRecord, self).verifyCredentials(credentials)

Modified: CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav/directory/idirectory.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav/directory/idirectory.py	2008-02-13 23:19:36 UTC (rev 2140)
+++ CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav/directory/idirectory.py	2008-02-13 23:32:53 UTC (rev 2141)
@@ -64,8 +64,14 @@
     def recordWithCalendarUserAddress(address):
         """
         @param address: the calendar user address of the record to look up.
-        @return: an L{IDirectoryRecord} provider with the given calendar user
-            address, or C{None} if no such record exists.
+        @return: an L{IDirectoryRecord} provider with the given
+            calendar user address, or C{None} if no such record is
+            found.  Note that some directory services may not be able
+            to locate records by calendar user address, or may return
+            partial results.  Note also that the calendar server may
+            add to the list of valid calendar user addresses for a
+            user, and the directory service may not be aware of these
+            addresses.
         """
 
 class IDirectoryRecord(Interface):

Modified: CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav/directory/principal.py	2008-02-13 23:19:36 UTC (rev 2140)
+++ CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav/directory/principal.py	2008-02-13 23:32:53 UTC (rev 2141)
@@ -90,7 +90,7 @@
         return self.principalForShortName(DirectoryService.recordType_users, user)
 
     def principalForGUID(self, guid):
-        return self.principalForUID(guid)
+        return self.principalForRecord(self.directory.recordWithGUID(guid))
 
     def principalForUID(self, uid):
         raise NotImplementedError("Subclass must implement principalForUID()")
@@ -98,7 +98,7 @@
     def principalForRecord(self, record):
         if record is None:
             return None
-        return self.principalForGUID(record.guid)
+        return self.principalForUID(record.guid)
 
     def principalForCalendarUserAddress(self, address):
         raise NotImplementedError("Subclass must implement principalForCalendarUserAddress()")

Modified: CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav/directory/test/test_opendirectory.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav/directory/test/test_opendirectory.py	2008-02-13 23:19:36 UTC (rev 2140)
+++ CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav/directory/test/test_opendirectory.py	2008-02-13 23:32:53 UTC (rev 2141)
@@ -66,7 +66,7 @@
                 service               = self.service(),
                 recordType            = DirectoryService.recordType_users,
                 guid                  = "B1F93EB1-DA93-4772-9141-81C250DA35B3",
-                nodename              = "/LDAPv2/127.0.0.1",
+                nodeName              = "/LDAPv2/127.0.0.1",
                 shortName             = "user",
                 fullName              = "Some user",
                 calendarUserAddresses = set(("mailtoguid at example.com",)),

Modified: CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav/directory/test/test_opendirectoryrecords.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav/directory/test/test_opendirectoryrecords.py	2008-02-13 23:19:36 UTC (rev 2140)
+++ CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav/directory/test/test_opendirectoryrecords.py	2008-02-13 23:32:53 UTC (rev 2141)
@@ -19,30 +19,35 @@
 import twisted.trial.unittest
 
 try:
-    from twistedcaldav.directory.appleopendirectory import OpenDirectoryService
+    from twistedcaldav.directory.appleopendirectory import OpenDirectoryService as RealOpenDirectoryService
     import dsattributes
 except ImportError:
     pass
 else:
     from twistedcaldav.directory.directory import DirectoryService
+    from twistedcaldav.directory.util import uuidFromName
 
-    def _queryDirectory(dir, recordType, shortName=None):
+    class OpenDirectoryService (RealOpenDirectoryService):
+        def _queryDirectory(directory, recordType, shortName=None, guid=None):
+            if shortName is None and guid is None:
+                return directory.fakerecords[recordType]
 
-        if shortName:
-            for name, record in dir.fakerecords[recordType]:
-                if name == shortName:
-                    return ((name, record),)
-            else:
-                return ()
-        else:
-            return dir.fakerecords[recordType]
+            assert shortName is None or guid is None
+            if guid is not None:
+                guid = guid.lower()
+
+            records = []
+
+            for name, record in directory.fakerecords[recordType]:
+                if name == shortName or record[dsattributes.kDS1AttrGeneratedUID] == guid:
+                    records.append((name, record))
+
+            return tuple(records)
     
     class ReloadCache(twisted.trial.unittest.TestCase):
-
         def setUp(self):
             super(ReloadCache, self).setUp()
             self._service = OpenDirectoryService(node="/Search", dosetup=False)
-            OpenDirectoryService._queryDirectory = _queryDirectory
             
         def tearDown(self):
             for call in self._service._delayedCalls:
@@ -58,82 +63,37 @@
             self.assertTrue(len(missing) == 0, msg="Directory records not found: %s" % (missing,))
             self.assertTrue(len(extras) == 0, msg="Directory records not expected: %s" % (extras,))
                 
-        def _verifyDisabledRecords(self, recordType, disabled_type, expected):
-            expected = set(expected)
-            found = self._service._records[recordType]["disabled_%s" % (disabled_type,)]
+        def _verifyDisabledRecords(self, recordType, expectedNames, expectedGUIDs):
+            def check(disabledType, expected):
+                expected = set(expected)
+                found = self._service._records[recordType][disabledType]
             
-            missing = expected.difference(found)
-            extras = found.difference(expected)
+                missing = expected.difference(found)
+                extras = found.difference(expected)
 
-            self.assertTrue(len(missing) == 0, msg="Disabled directory records not found: %s" % (missing,))
-            self.assertTrue(len(extras) == 0, msg="Disabled directory records not expected: %s" % (extras,))
+                self.assertTrue(len(missing) == 0, msg="Disabled directory records not found: %s" % (missing,))
+                self.assertTrue(len(extras) == 0, msg="Disabled directory records not expected: %s" % (extras,))
 
-        def test_Normal(self):
-            
+            check("disabled names", expectedNames)
+            check("disabled guids", (guid.lower() for guid in expectedGUIDs))
+
+        def test_normal(self):
             self._service.fakerecords = {
                 DirectoryService.recordType_users: [
-                    ["user01", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_user01",
-                        dsattributes.kDS1AttrDistinguishedName: "User 01",
-                        dsattributes.kDSNAttrEMailAddress: "user01 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
-                    ["user02", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_user02",
-                        dsattributes.kDS1AttrDistinguishedName: "User 02",
-                        dsattributes.kDSNAttrEMailAddress: "user02 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
+                    fakeODRecord("User 01"),
+                    fakeODRecord("User 02"),
                 ],
                 DirectoryService.recordType_groups: [
-                    ["group01", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_group01",
-                        dsattributes.kDS1AttrDistinguishedName: "Group 01",
-                        dsattributes.kDSNAttrEMailAddress: "group01 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
-                    ["group02", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_group02",
-                        dsattributes.kDS1AttrDistinguishedName: "Group 02",
-                        dsattributes.kDSNAttrEMailAddress: "group02 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
+                    fakeODRecord("Group 01"),
+                    fakeODRecord("Group 02"),
                 ],
                 DirectoryService.recordType_resources: [
-                    ["resource01", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_resource01",
-                        dsattributes.kDS1AttrDistinguishedName: "Resource 01",
-                        dsattributes.kDSNAttrEMailAddress: "resource01 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
-                    ["resource02", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_resource02",
-                        dsattributes.kDS1AttrDistinguishedName: "Resource 02",
-                        dsattributes.kDSNAttrEMailAddress: "resource02 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
+                    fakeODRecord("Resource 01"),
+                    fakeODRecord("Resource 02"),
                 ],
                 DirectoryService.recordType_locations: [
-                    ["location01", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_location01",
-                        dsattributes.kDS1AttrDistinguishedName: "Location 01",
-                        dsattributes.kDSNAttrEMailAddress: "location01 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
-                    ["location02", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_location02",
-                        dsattributes.kDS1AttrDistinguishedName: "Location 02",
-                        dsattributes.kDSNAttrEMailAddress: "location02 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
+                    fakeODRecord("Location 01"),
+                    fakeODRecord("Location 02"),
                 ],
             }
 
@@ -142,221 +102,173 @@
             self._service.reloadCache(DirectoryService.recordType_resources)
             self._service.reloadCache(DirectoryService.recordType_locations)
 
-            self._verifyRecords(DirectoryService.recordType_users, ("user01", "user02",))
-            self._verifyDisabledRecords(DirectoryService.recordType_users, "names", ())
-            self._verifyDisabledRecords(DirectoryService.recordType_users, "guids", ())
+            self._verifyRecords(DirectoryService.recordType_users, ("user01", "user02"))
+            self._verifyDisabledRecords(DirectoryService.recordType_users, (), ())
 
-            self._verifyRecords(DirectoryService.recordType_groups, ("group01", "group02",))
-            self._verifyDisabledRecords(DirectoryService.recordType_groups, "names", ())
-            self._verifyDisabledRecords(DirectoryService.recordType_groups, "guids", ())
+            self._verifyRecords(DirectoryService.recordType_groups, ("group01", "group02"))
+            self._verifyDisabledRecords(DirectoryService.recordType_groups, (), ())
 
-            self._verifyRecords(DirectoryService.recordType_resources, ("resource01", "resource02",))
-            self._verifyDisabledRecords(DirectoryService.recordType_resources, "names", ())
-            self._verifyDisabledRecords(DirectoryService.recordType_resources, "guids", ())
+            self._verifyRecords(DirectoryService.recordType_resources, ("resource01", "resource02"))
+            self._verifyDisabledRecords(DirectoryService.recordType_resources, (), ())
 
-            self._verifyRecords(DirectoryService.recordType_locations, ("location01", "location02",))
-            self._verifyDisabledRecords(DirectoryService.recordType_locations, "names", ())
-            self._verifyDisabledRecords(DirectoryService.recordType_locations, "guids", ())
+            self._verifyRecords(DirectoryService.recordType_locations, ("location01", "location02"))
+            self._verifyDisabledRecords(DirectoryService.recordType_locations, (), ())
 
-        def test_DuplicateRecords(self):
+        def test_normalCacheMiss(self):
             self._service.fakerecords = {
                 DirectoryService.recordType_users: [
-                    ["user01", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_user01",
-                        dsattributes.kDS1AttrDistinguishedName: "User 01",
-                        dsattributes.kDSNAttrEMailAddress: "user01 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
-                    ["user02", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_user02",
-                        dsattributes.kDS1AttrDistinguishedName: "User 02",
-                        dsattributes.kDSNAttrEMailAddress: "user02 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
-                    ["user02", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_user02",
-                        dsattributes.kDS1AttrDistinguishedName: "User 02",
-                        dsattributes.kDSNAttrEMailAddress: "user02 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
+                    fakeODRecord("User 01"),
                 ],
             }
 
             self._service.reloadCache(DirectoryService.recordType_users)
 
-            self._verifyRecords(DirectoryService.recordType_users, ("user01", "user02",))
-            self._verifyDisabledRecords(DirectoryService.recordType_users, "names", ())
-            self._verifyDisabledRecords(DirectoryService.recordType_users, "guids", ())
+            self._verifyRecords(DirectoryService.recordType_users, ("user01",))
+            self._verifyDisabledRecords(DirectoryService.recordType_users, (), ())
 
+            self._service.fakerecords = {
+                DirectoryService.recordType_users: [
+                    fakeODRecord("User 01"),
+                    fakeODRecord("User 02"),
+                    fakeODRecord("User 03", guid="D10F3EE0-5014-41D3-8488-3819D3EF3B2A"),
+                ],
+            }
 
-        def test_DuplicateName(self):
-            
+            self._service.reloadCache(DirectoryService.recordType_users, shortName="user02")
+            self._service.reloadCache(DirectoryService.recordType_users, guid="D10F3EE0-5014-41D3-8488-3819D3EF3B2A")
+
+            self._verifyRecords(DirectoryService.recordType_users, ("user01", "user02", "user03"))
+            self._verifyDisabledRecords(DirectoryService.recordType_users, (), ())
+
+        def test_duplicateRecords(self):
             self._service.fakerecords = {
                 DirectoryService.recordType_users: [
-                    ["user01", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_user01",
-                        dsattributes.kDS1AttrDistinguishedName: "User 01",
-                        dsattributes.kDSNAttrEMailAddress: "user01 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
-                    ["user02", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_user02-1",
-                        dsattributes.kDS1AttrDistinguishedName: "User 02",
-                        dsattributes.kDSNAttrEMailAddress: "user02 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
-                    ["user02", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_user02-2",
-                        dsattributes.kDS1AttrDistinguishedName: "User 02",
-                        dsattributes.kDSNAttrEMailAddress: "user02 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
+                    fakeODRecord("User 01"),
+                    fakeODRecord("User 02"),
+                    fakeODRecord("User 02"),
                 ],
             }
 
             self._service.reloadCache(DirectoryService.recordType_users)
 
+            self._verifyRecords(DirectoryService.recordType_users, ("user01", "user02"))
+            self._verifyDisabledRecords(DirectoryService.recordType_users, (), ())
+            self._verifyDisabledRecords(DirectoryService.recordType_users, (), ())
+
+
+        def test_duplicateName(self):
+            self._service.fakerecords = {
+                DirectoryService.recordType_users: [
+                    fakeODRecord("User 01"),
+                    fakeODRecord("User 02", guid="A25775BB-1281-4606-98C6-2893B2D5CCD7"),
+                    fakeODRecord("User 02", guid="30CA2BB9-C935-4A5D-80E2-79266BCB0255"),
+                ],
+            }
+
+            self._service.reloadCache(DirectoryService.recordType_users)
+
             self._verifyRecords(DirectoryService.recordType_users, ("user01",))
-            self._verifyDisabledRecords(DirectoryService.recordType_users, "names", ("user02",))
-            self._verifyDisabledRecords(DirectoryService.recordType_users, "guids", ("GUID_user02-1", "GUID_user02-2", ))
+            self._verifyDisabledRecords(
+                DirectoryService.recordType_users,
+                ("user02",),
+                ("A25775BB-1281-4606-98C6-2893B2D5CCD7", "30CA2BB9-C935-4A5D-80E2-79266BCB0255"),
+            )
 
-        def test_DuplicateGUID(self):
-            
+        def test_duplicateGUID(self):
             self._service.fakerecords = {
                 DirectoryService.recordType_users: [
-                    ["user01", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_user01",
-                        dsattributes.kDS1AttrDistinguishedName: "User 01",
-                        dsattributes.kDSNAttrEMailAddress: "user01 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
-                    ["user02", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_user02",
-                        dsattributes.kDS1AttrDistinguishedName: "User 02",
-                        dsattributes.kDSNAttrEMailAddress: "user02 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
-                    ["user03", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_user02",
-                        dsattributes.kDS1AttrDistinguishedName: "User 02",
-                        dsattributes.kDSNAttrEMailAddress: "user02 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
+                    fakeODRecord("User 01"),
+                    fakeODRecord("User 02", guid="113D7F74-F84A-4F17-8C96-CE8F10D68EF8"),
+                    fakeODRecord("User 03", guid="113D7F74-F84A-4F17-8C96-CE8F10D68EF8"),
                 ],
             }
 
             self._service.reloadCache(DirectoryService.recordType_users)
 
             self._verifyRecords(DirectoryService.recordType_users, ("user01",))
-            self._verifyDisabledRecords(DirectoryService.recordType_users, "names", ("user02", "user03",))
-            self._verifyDisabledRecords(DirectoryService.recordType_users, "guids", ("GUID_user02", ))
+            self._verifyDisabledRecords(
+                DirectoryService.recordType_users,
+                ("user02", "user03"),
+                ("113D7F74-F84A-4F17-8C96-CE8F10D68EF8",),
+            )
 
-        def test_DuplicateCombo(self):
-            
+        def test_duplicateCombo(self):
             self._service.fakerecords = {
                 DirectoryService.recordType_users: [
-                    ["user01", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_user01",
-                        dsattributes.kDS1AttrDistinguishedName: "User 01",
-                        dsattributes.kDSNAttrEMailAddress: "user01 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
-                    ["user02", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_user02",
-                        dsattributes.kDS1AttrDistinguishedName: "User 02",
-                        dsattributes.kDSNAttrEMailAddress: "user02 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
-                    ["user03", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_user02",
-                        dsattributes.kDS1AttrDistinguishedName: "User 02",
-                        dsattributes.kDSNAttrEMailAddress: "user02 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
-                    ["user02", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_user02-2",
-                        dsattributes.kDS1AttrDistinguishedName: "User 02",
-                        dsattributes.kDSNAttrEMailAddress: "user02 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
+                    fakeODRecord("User 01"),
+                    fakeODRecord("User 02", guid="113D7F74-F84A-4F17-8C96-CE8F10D68EF8"),
+                    fakeODRecord("User 02", guid="113D7F74-F84A-4F17-8C96-CE8F10D68EF8", shortName="user03"),
+                    fakeODRecord("User 02", guid="136E369F-DB40-4135-878D-B75D38242D39"),
                 ],
             }
 
             self._service.reloadCache(DirectoryService.recordType_users)
 
             self._verifyRecords(DirectoryService.recordType_users, ("user01",))
-            self._verifyDisabledRecords(DirectoryService.recordType_users, "names", ("user02", "user03",))
-            self._verifyDisabledRecords(DirectoryService.recordType_users, "guids", ("GUID_user02", "GUID_user02-2"))
+            self._verifyDisabledRecords(
+                DirectoryService.recordType_users,
+                ("user02", "user03"),
+                ("113D7F74-F84A-4F17-8C96-CE8F10D68EF8", "136E369F-DB40-4135-878D-B75D38242D39"),
+            )
 
-        def test_DuplicateGUIDCacheMiss(self):
-            
+        def test_duplicateGUIDCacheMiss(self):
             self._service.fakerecords = {
                 DirectoryService.recordType_users: [
-                    ["user01", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_user01",
-                        dsattributes.kDS1AttrDistinguishedName: "User 01",
-                        dsattributes.kDSNAttrEMailAddress: "user01 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
-                    ["user02", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_user02",
-                        dsattributes.kDS1AttrDistinguishedName: "User 02",
-                        dsattributes.kDSNAttrEMailAddress: "user02 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
+                    fakeODRecord("User 01"),
+                    fakeODRecord("User 02", guid="EDB9EE55-31F2-4EA9-B5FB-D8AE2A8BA35E"),
+                    fakeODRecord("User 03", guid="D10F3EE0-5014-41D3-8488-3819D3EF3B2A"),
                 ],
             }
 
             self._service.reloadCache(DirectoryService.recordType_users)
 
-            self._verifyRecords(DirectoryService.recordType_users, ("user01", "user02",))
-            self._verifyDisabledRecords(DirectoryService.recordType_users, "names", ())
-            self._verifyDisabledRecords(DirectoryService.recordType_users, "guids", ())
+            self._verifyRecords(DirectoryService.recordType_users, ("user01", "user02", "user03"))
+            self._verifyDisabledRecords(DirectoryService.recordType_users, (), ())
             
             self._service.fakerecords = {
                 DirectoryService.recordType_users: [
-                    ["user01", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_user01",
-                        dsattributes.kDS1AttrDistinguishedName: "User 01",
-                        dsattributes.kDSNAttrEMailAddress: "user01 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
-                    ["user02", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_user02",
-                        dsattributes.kDS1AttrDistinguishedName: "User 02",
-                        dsattributes.kDSNAttrEMailAddress: "user02 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
-                    ["user03", {
-                        dsattributes.kDS1AttrGeneratedUID: "GUID_user02",
-                        dsattributes.kDS1AttrDistinguishedName: "User 02",
-                        dsattributes.kDSNAttrEMailAddress: "user02 at example.com",
-                        dsattributes.kDSNAttrServicesLocator: "12345:67890:calendar",
-                        dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
-                    }],
+                    fakeODRecord("User 01"),
+                    fakeODRecord("User 02", guid="EDB9EE55-31F2-4EA9-B5FB-D8AE2A8BA35E"),
+                    fakeODRecord("User 02", guid="EDB9EE55-31F2-4EA9-B5FB-D8AE2A8BA35E", shortName="user04"),
+                    fakeODRecord("User 03", guid="62368DDF-0C62-4C97-9A58-DE9FD46131A0"),
+                    fakeODRecord("User 03", guid="62368DDF-0C62-4C97-9A58-DE9FD46131A0", shortName="user05"),
                 ],
             }
 
-            self._service.reloadCache(DirectoryService.recordType_users, "user03")
+            self._service.reloadCache(DirectoryService.recordType_users, shortName="user04")
+            self._service.reloadCache(DirectoryService.recordType_users, guid="62368DDF-0C62-4C97-9A58-DE9FD46131A0")
 
-            self._verifyRecords(DirectoryService.recordType_users, ("user01", "user02",))
-            self._verifyDisabledRecords(DirectoryService.recordType_users, "names", ("user03",))
-            self._verifyDisabledRecords(DirectoryService.recordType_users, "guids", ("GUID_user02", ))
+            self._verifyRecords(DirectoryService.recordType_users, ("user01",))
+            self._verifyDisabledRecords(
+                DirectoryService.recordType_users,
+                ("user02", "user03", "user04", "user05"),
+                ("EDB9EE55-31F2-4EA9-B5FB-D8AE2A8BA35E", "62368DDF-0C62-4C97-9A58-DE9FD46131A0", "D10F3EE0-5014-41D3-8488-3819D3EF3B2A"),
+            )
 
+def fakeODRecord(fullName, shortName=None, guid=None, email=None):
+    if shortName is None:
+        shortName = shortNameForFullName(fullName)
+
+    if guid is None:
+        guid = guidForShortName(shortName)
+    else:
+        guid = guid.lower()
+
+    if email is None:
+        email = "%s at example.com" % (shortName,)
+
+    return [
+        shortName, {
+            dsattributes.kDS1AttrDistinguishedName: fullName,
+            dsattributes.kDS1AttrGeneratedUID: guid,
+            dsattributes.kDSNAttrEMailAddress: email,
+            dsattributes.kDSNAttrServicesLocator: "FE588D50-0514-4DF9-BCB5-8ECA5F3DA274:030572AE-ABEC-4E0F-83C9-FCA304769E5F:calendar",
+            dsattributes.kDSNAttrMetaNodeLocation: "/LDAPv3/127.0.0.1",
+        }
+    ]
+
+def shortNameForFullName(fullName):
+    return fullName.lower().replace(" ", "")
+
+def guidForShortName(shortName):
+    return uuidFromName(OpenDirectoryService.baseGUID, shortName)

Modified: CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav/directory/test/test_opendirectoryschema.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav/directory/test/test_opendirectoryschema.py	2008-02-13 23:19:36 UTC (rev 2140)
+++ CalendarServer/branches/release/CalendarServer-1.2-dev/twistedcaldav/directory/test/test_opendirectoryschema.py	2008-02-13 23:32:53 UTC (rev 2141)
@@ -977,7 +977,7 @@
                 self.assertEqual(service.servicetags.pop(), "GUIDIFY:C18C34AC-3D9E-403C-8A33-BFC303F3840E:calendar")
 
         def test_expandcuaddrs(self):
-            def _doTest(recordName, record, result, title):
+            def doTest(recordName, record, result, title):
                 service = OpenDirectoryService(node="/Search", dosetup=False)
                 if not service._parseServiceInfo("calendar.apple.com", recordName, {
                 'dsAttrTypeNative:apple-serviceinfo'  : PlistParse.plist_good,
@@ -985,7 +985,7 @@
                 dsattributes.kDSNAttrMetaNodeLocation:  "/LDAPv3/127.0.0.1"}):
                     self.fail(msg="Plist parse should not have failed: %s" % (recordName,))
                 else:
-                    expanded = service._getCalendarUserAddresses(DirectoryService.recordType_users, recordName, record)
+                    expanded = service._calendarUserAddresses(DirectoryService.recordType_users, recordName, record)
 
                     # Verify that we extracted the proper items
                     self.assertEqual(expanded, result, msg=title % (expanded, result,))
@@ -1025,7 +1025,7 @@
             )
 
             for recordName, record, result, title in data:
-                _doTest(recordName, record, result, title)
+                doTest(recordName, record, result, title)
 
     class ODRecordsParse (twisted.trial.unittest.TestCase):
 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20080213/4d761f11/attachment-0001.html


More information about the calendarserver-changes mailing list