[CalendarServer-changes] [12331] twext/trunk/twext/who

source_changes at macosforge.org source_changes at macosforge.org
Wed Mar 12 11:24:15 PDT 2014


Revision: 12331
          http://trac.calendarserver.org//changeset/12331
Author:   wsanchez at apple.com
Date:     2014-01-13 16:38:59 -0800 (Mon, 13 Jan 2014)
Log Message:
-----------
Start work on basic queries.

Modified Paths:
--------------
    twext/trunk/twext/who/idirectory.py
    twext/trunk/twext/who/ldap/_constants.py
    twext/trunk/twext/who/ldap/_service.py
    twext/trunk/twext/who/ldap/_util.py
    twext/trunk/twext/who/ldap/test/test_service.py
    twext/trunk/twext/who/ldap/test/test_util.py
    twext/trunk/twext/who/test/test_directory.py

Modified: twext/trunk/twext/who/idirectory.py
===================================================================
--- twext/trunk/twext/who/idirectory.py	2014-01-14 00:20:20 UTC (rev 12330)
+++ twext/trunk/twext/who/idirectory.py	2014-01-14 00:38:59 UTC (rev 12331)
@@ -220,7 +220,7 @@
     @staticmethod
     def valueType(name):
         """
-        Check for the expected type of values for a field.
+        Look up the expected type for values of a field.
 
         @param name: The name of the field.
         @type name: L{NamedConstant}

Modified: twext/trunk/twext/who/ldap/_constants.py
===================================================================
--- twext/trunk/twext/who/ldap/_constants.py	2014-01-14 00:20:20 UTC (rev 12330)
+++ twext/trunk/twext/who/ldap/_constants.py	2014-01-14 00:38:59 UTC (rev 12331)
@@ -22,6 +22,9 @@
     Names, NamedConstant, Values, ValueConstant
 )
 
+from ..idirectory import (
+    FieldName as BaseFieldName, RecordType as BaseRecordType
+)
 from ..expression import MatchType
 
 
@@ -153,7 +156,7 @@
     teletexTerminalIdentifier = ValueConstant(u"teletexTerminalIdentifier")
     telexNumber = ValueConstant(u"telexNumber")
     title = ValueConstant(u"title")
-    userid = ValueConstant(u"uid")
+    userID = ValueConstant(u"uid")
     uniqueMember = ValueConstant(u"uniqueMember")
     userPassword = ValueConstant(u"userPassword")
     x121Address = ValueConstant(u"x121Address")
@@ -190,3 +193,23 @@
 # http://tools.ietf.org/html/rfc2307
 # http://tools.ietf.org/html/rfc2798
 # http://tools.ietf.org/html/rfc2739 calendar
+
+
+
+# Maps field name -> LDAP attribute name
+DEFAULT_FIELDNAME_MAP = {
+    BaseFieldName.uid: u"uid",  # FIXME
+    BaseFieldName.guid: u"entryUUID",  # FIXME
+    BaseFieldName.recordType: u"objectClass",
+    BaseFieldName.shortNames: RFC4519Attribute.userID.value,
+    BaseFieldName.fullNames: RFC4519Attribute.commonName.value,
+    BaseFieldName.emailAddresses: u"mail",  # FIXME
+    BaseFieldName.password: u"userPassword",  # FIXME
+}
+
+
+# Maps record type -> LDAP organizational unit name
+DEFAULT_RECORDTYPE_MAP = {
+    BaseRecordType.user: u"People",  # FIXME
+    BaseRecordType.group: u"Group",  # FIXME
+}

Modified: twext/trunk/twext/who/ldap/_service.py
===================================================================
--- twext/trunk/twext/who/ldap/_service.py	2014-01-14 00:20:20 UTC (rev 12330)
+++ twext/trunk/twext/who/ldap/_service.py	2014-01-14 00:38:59 UTC (rev 12331)
@@ -34,7 +34,8 @@
 
 from ..idirectory import (
     DirectoryServiceError, DirectoryAvailabilityError,
-    # InvalidDirectoryRecordError, QueryNotSupportedError,
+    # InvalidDirectoryRecordError,
+    # QueryNotSupportedError,
     # FieldName as BaseFieldName,
     RecordType as BaseRecordType,
     # IPlaintextPasswordVerifier, IHTTPDigestVerifier,
@@ -43,17 +44,21 @@
     DirectoryService as BaseDirectoryService,
     DirectoryRecord as BaseDirectoryRecord,
 )
-# from ..expression import (
-#     CompoundExpression, Operand,
-#     MatchExpression, MatchFlags,
-# )
+from ..expression import (
+    # CompoundExpression, Operand,
+    MatchExpression,  # MatchFlags,
+)
 from ..util import (
     # iterFlags,
     ConstantsContainer,
 )
-# from ._constants import LDAP_QUOTING_TABLE
+from ._constants import DEFAULT_FIELDNAME_MAP, DEFAULT_RECORDTYPE_MAP
+from ._util import (
+    ldapQueryStringFromMatchExpression,
+    ldapQueryStringFromCompoundExpression,
+    # ldapQueryStringFromExpression,
+)
 
-DEFAULT_URL = "ldap://localhost/"
 
 
 #
@@ -121,16 +126,20 @@
 
     def __init__(
         self,
-        url=DEFAULT_URL,
+        url,
+        baseDN,
         credentials=None,
         timeout=None,
         tlsCACertificateFile=None,
         tlsCACertificateDirectory=None,
         useTLS=False,
         debug=False,
+        fieldNameMap=DEFAULT_FIELDNAME_MAP,
+        recordTypeMap=DEFAULT_RECORDTYPE_MAP,
     ):
         self.url = url
-        self.credentials = credentials
+        self._baseDN = baseDN
+        self._credentials = credentials
         self._timeout = timeout
 
         if tlsCACertificateFile is None:
@@ -150,7 +159,10 @@
         else:
             self._debug = None
 
+        self._fieldNameMap = fieldNameMap
+        self._recordTypeMap = recordTypeMap
 
+
     @property
     def realmName(self):
         return u"{self.url}".format(self=self)
@@ -186,33 +198,33 @@
                 self.log.info("Starting TLS for {source.url}")
                 yield deferToThread(connection.start_tls_s)
 
-            if self.credentials is not None:
-                if IUsernamePassword.providedBy(self.credentials):
+            if self._credentials is not None:
+                if IUsernamePassword.providedBy(self._credentials):
                     try:
                         yield deferToThread(
                             connection.simple_bind_s,
-                            self.credentials.username,
-                            self.credentials.password,
+                            self._credentials.username,
+                            self._credentials.password,
                         )
                         self.log.info(
                             "Bound to LDAP as {credentials.username}",
-                            credentials=self.credentials
+                            credentials=self._credentials
                         )
                     except (
                         ldap.INVALID_CREDENTIALS, ldap.INVALID_DN_SYNTAX
                     ) as e:
                         self.log.error(
                             "Unable to bind to LDAP as {credentials.username}",
-                            credentials=self.credentials
+                            credentials=self._credentials
                         )
                         raise LDAPBindAuthError(
-                            self.credentials.username, e
+                            self._credentials.username, e
                         )
 
                 else:
                     raise LDAPConnectionError(
                         "Unknown credentials type: {0}"
-                        .format(self.credentials)
+                        .format(self._credentials)
                     )
 
             self._connection = connection
@@ -220,7 +232,51 @@
         returnValue(self._connection)
 
 
+    @inlineCallbacks
+    def _recordsFromQueryString(self, queryString):
+        connection = yield self._connect()
 
+        # print("+" * 80)
+        # print("Query:", repr(queryString))
+
+        reply = connection.search_s(
+            self._baseDN, ldap.SCOPE_SUBTREE, queryString  # attrs
+        )
+
+        # print("Reply:", repr(reply))
+        # print("+" * 80)
+
+        records = []
+
+        for recordData in reply:
+            raise NotImplementedError(reply)
+
+        returnValue(records)
+
+
+    def recordsFromNonCompoundExpression(self, expression, records=None):
+        if isinstance(expression, MatchExpression):
+            queryString = ldapQueryStringFromMatchExpression(
+                expression, self._fieldNameMap, self._recordTypeMap
+            )
+            return self._recordsFromQueryString(queryString)
+
+        return BaseDirectoryService.recordsFromNonCompoundExpression(
+            self, expression, records=records
+        )
+
+
+    def recordsFromCompoundExpression(self, expression, records=None):
+        if not expression.expressions:
+            return ()
+
+        queryString = ldapQueryStringFromCompoundExpression(
+            expression, self._fieldNameMap, self._recordTypeMap
+        )
+        return self._recordsFromQueryString(queryString)
+
+
+
 class DirectoryRecord(BaseDirectoryRecord):
     """
     LDAP directory record.

Modified: twext/trunk/twext/who/ldap/_util.py
===================================================================
--- twext/trunk/twext/who/ldap/_util.py	2014-01-14 00:20:20 UTC (rev 12330)
+++ twext/trunk/twext/who/ldap/_util.py	2014-01-14 00:38:59 UTC (rev 12331)
@@ -15,7 +15,7 @@
 # limitations under the License.
 ##
 
-from ..idirectory import QueryNotSupportedError
+from ..idirectory import QueryNotSupportedError, FieldName
 from ..expression import (
     CompoundExpression, Operand,
     MatchExpression, MatchFlags,
@@ -25,23 +25,29 @@
 
 
 
-def ldapQueryStringFromMatchExpression(expression, attrMap):
+def ldapQueryStringFromMatchExpression(
+    expression, fieldNameMap, recordTypeMap
+):
     """
     Generates an LDAP query string from a match expression.
 
     @param expression: A match expression.
     @type expression: L{MatchExpression}
 
-    @param attrMap: A mapping from L{FieldName}s to native LDAP attribute
+    @param fieldNameMap: A mapping from L{FieldName}s to native LDAP attribute
         names.
-    @type attrMap: L{dict}
+    @type fieldNameMap: L{dict}
 
+    @param recordTypeMap: A mapping from L{RecordType}s to native LDAP object
+        class names.
+    @type recordTypeMap: L{dict}
+
     @return: An LDAP query string.
     @rtype: C{unicode}
 
     @raises QueryNotSupportedError: If the expression's match type is unknown,
         or if the expresion references an unknown field name (meaning a field
-        name not in C{attrMap}).
+        name not in C{fieldNameMap}).
     """
     matchType = LDAPMatchType.fromMatchType(expression.matchType)
     if matchType is None:
@@ -63,14 +69,24 @@
     # if MatchFlags.caseInsensitive not in flags:
     #     raise NotImplementedError("Need to handle case sensitive")
 
+    fieldName = expression.fieldName
     try:
-        attribute = attrMap[expression.fieldName]
+        attribute = fieldNameMap[fieldName]
     except KeyError:
         raise QueryNotSupportedError(
-            "Unknown field name: {0}".format(expression.fieldName)
+            "Unmapped field name: {0}".format(expression.fieldName)
         )
 
-    value = unicode(expression.fieldValue)       # We want unicode
+    if fieldName is FieldName.recordType:
+        try:
+            value = recordTypeMap[expression.fieldValue]
+        except KeyError:
+            raise QueryNotSupportedError(
+                "Unmapped record type: {0}".format(expression.fieldValue)
+            )
+    else:
+        value = unicode(expression.fieldValue)
+
     value = value.translate(LDAP_QUOTING_TABLE)  # Escape special chars
 
     return matchType.queryString.format(
@@ -78,16 +94,18 @@
     )
 
 
-def ldapQueryStringFromCompoundExpression(expression, attrMap):
+def ldapQueryStringFromCompoundExpression(
+    expression, fieldNameMap, recordTypeMap
+):
     """
     Generates an LDAP query string from a compound expression.
 
     @param expression: A compound expression.
     @type expression: L{MatchExpression}
 
-    @param attrMap: A mapping from L{FieldName}s to native LDAP attribute
+    @param fieldNameMap: A mapping from L{FieldName}s to native LDAP attribute
         names.
-    @type attrMap: L{dict}
+    @type fieldNameMap: L{dict}
 
     @return: An LDAP query string.
     @rtype: C{unicode}
@@ -107,7 +125,9 @@
 
     for subExpression in expression.expressions:
         queryTokens.append(
-            ldapQueryStringFromExpression(subExpression, attrMap)
+            ldapQueryStringFromExpression(
+                subExpression, fieldNameMap, recordTypeMap
+            )
         )
 
     if len(expression.expressions) > 1:
@@ -116,13 +136,15 @@
     return u"".join(queryTokens)
 
 
-def ldapQueryStringFromExpression(expression, attrMap):
+def ldapQueryStringFromExpression(
+    expression, fieldNameMap, recordTypeMap
+):
     """
     Converts an expression into an LDAP query string.
 
-    @param attrMap: A mapping from L{FieldName}s to native LDAP attribute
+    @param fieldNameMap: A mapping from L{FieldName}s to native LDAP attribute
         names.
-    @type attrMap: L{dict}
+    @type fieldNameMap: L{dict}
 
     @param expression: An expression.
     @type expression: L{MatchExpression} or L{CompoundExpression}
@@ -135,10 +157,14 @@
     """
 
     if isinstance(expression, MatchExpression):
-        return ldapQueryStringFromMatchExpression(expression, attrMap)
+        return ldapQueryStringFromMatchExpression(
+            expression, fieldNameMap, recordTypeMap
+        )
 
     if isinstance(expression, CompoundExpression):
-        return ldapQueryStringFromCompoundExpression(expression, attrMap)
+        return ldapQueryStringFromCompoundExpression(
+            expression, fieldNameMap, recordTypeMap
+        )
 
     raise QueryNotSupportedError(
         "Unknown expression type: {0!r}".format(expression)

Modified: twext/trunk/twext/who/ldap/test/test_service.py
===================================================================
--- twext/trunk/twext/who/ldap/test/test_service.py	2014-01-14 00:20:20 UTC (rev 12330)
+++ twext/trunk/twext/who/ldap/test/test_service.py	2014-01-14 00:38:59 UTC (rev 12331)
@@ -29,17 +29,22 @@
 from twisted.cred.credentials import UsernamePassword
 from twisted.trial import unittest
 
+from ...idirectory import FieldName as BaseFieldName
 # from ...expression import (
 #     CompoundExpression, Operand, MatchExpression, MatchType, MatchFlags
 # )
 from .._service import (
-    DEFAULT_URL,
+    DEFAULT_FIELDNAME_MAP, DEFAULT_RECORDTYPE_MAP,
     LDAPBindAuthError,
     DirectoryService, DirectoryRecord,
 )
 
 from ...test import test_directory
-from ...test.test_xml import xmlService
+from ...test.test_xml import (
+    xmlService,
+    DirectoryServiceConvenienceTestMixIn
+    as BaseDirectoryServiceConvenienceTestMixIn,
+)
 
 
 class BaseTestCase(object):
@@ -47,12 +52,23 @@
     Tests for L{DirectoryService}.
     """
 
-    url = DEFAULT_URL
-    realmName = unicode(DEFAULT_URL)
+    url = "ldap://localhost/"
+    baseDN = u"o=org"
+    realmName = unicode(url)
 
 
     def setUp(self):
-        self.mockLDAP = MockLdap(mockDirectoryDataFromXML(self.mktemp()))
+        self.xmlSeedService = xmlService(self.mktemp())
+        self.mockData = mockDirectoryDataFromXMLService(self.xmlSeedService)
+
+        if False:
+            from pprint import pprint
+            print("")
+            print("-" * 80)
+            pprint(self.mockData)
+            print("-" * 80)
+
+        self.mockLDAP = MockLdap(self.mockData)
         self.mockLDAP.start()
 
 
@@ -61,25 +77,50 @@
 
 
     def service(self, **kwargs):
-        return DirectoryService(**kwargs)
+        return DirectoryService(url=self.url, baseDN=self.baseDN, **kwargs)
 
 
 
-class DirectoryServiceConvenienceTestMixIn(object):
+class DirectoryServiceConvenienceTestMixIn(
+    BaseDirectoryServiceConvenienceTestMixIn
+):
     def _unimplemented(self):
         raise NotImplementedError()
 
     _unimplemented.todo = "unimplemented"
 
 
-    test_recordWithUID = _unimplemented
-    test_recordWithGUID = _unimplemented
-    test_recordsWithRecordType = _unimplemented
-    test_recordWithShortName = _unimplemented
-    test_recordsWithEmailAddress = _unimplemented
+    def test_recordWithUID(self):
+        return BaseDirectoryServiceConvenienceTestMixIn.test_recordWithUID(self)
 
+    test_recordWithUID.todo = "needs a seed"
 
 
+    def test_recordWithGUID(self):
+        return BaseDirectoryServiceConvenienceTestMixIn.test_recordWithGUID(self)
+
+    test_recordWithGUID.todo = "needs a seed"
+
+
+    def test_recordsWithRecordType(self):
+        return BaseDirectoryServiceConvenienceTestMixIn.test_recordsWithRecordType(self)
+
+    test_recordsWithRecordType.todo = "needs a seed"
+
+
+    def test_recordWithShortName(self):
+        return BaseDirectoryServiceConvenienceTestMixIn.test_recordWithShortName(self)
+
+    test_recordWithShortName.todo = "needs a seed"
+
+
+    def test_recordsWithEmailAddress(self):
+        return BaseDirectoryServiceConvenienceTestMixIn.test_recordsWithEmailAddress(self)
+
+    test_recordsWithEmailAddress.todo = "needs a seed"
+
+
+
 class DirectoryServiceConnectionTestMixIn(object):
     @inlineCallbacks
     def test_connect_defaults(self):
@@ -195,9 +236,7 @@
 
 
 
-def mockDirectoryDataFromXML(tmp):
-    service = xmlService(tmp)
-
+def mockDirectoryDataFromXMLService(service):
     o = u"org"
     ou = u"calendarserver"
 
@@ -206,17 +245,6 @@
         u"ou={ou}".format(ou=ou): dict(ou=ou),
     }
 
-    def toAttribute(fieldName):
-        return unicode({
-            service.fieldName.uid: u"recordid",
-            service.fieldName.guid: u"guid",
-            service.fieldName.recordType: u"objectclass",
-            service.fieldName.shortNames: u"uid",
-            service.fieldName.fullNames: u"cn",
-            service.fieldName.emailAddresses: u"mail",
-            service.fieldName.password: u"userPassword",
-        }.get(fieldName, fieldName.name))
-
     def toUnicode(obj):
         if isinstance(obj, (NamedConstant, ValueConstant)):
             return obj.name
@@ -227,8 +255,13 @@
         return unicode(obj)
 
     def tuplify(record, fieldName):
-        name = toAttribute(fieldName)
-        value = toUnicode(record.fields[fieldName])
+        name = DEFAULT_FIELDNAME_MAP.get(fieldName, fieldName.name)
+
+        if fieldName is BaseFieldName.recordType:
+            value = DEFAULT_RECORDTYPE_MAP[record.fields[fieldName]]
+        else:
+            value = toUnicode(record.fields[fieldName])
+
         return (name, value)
 
     for records in service.index[service.fieldName.uid].itervalues():
@@ -245,10 +278,4 @@
 
             data[dn] = recordData
 
-    # from pprint import pprint
-    # print("")
-    # print("-" * 80)
-    # pprint(data)
-    # print("-" * 80)
-
     return data

Modified: twext/trunk/twext/who/ldap/test/test_util.py
===================================================================
--- twext/trunk/twext/who/ldap/test/test_util.py	2014-01-14 00:20:20 UTC (rev 12330)
+++ twext/trunk/twext/who/ldap/test/test_util.py	2014-01-14 00:38:59 UTC (rev 12331)
@@ -38,7 +38,13 @@
     Tests for LDAP query generation.
     """
 
-    def attrMap(self, service):
+    def service(self):
+        # Use intentionally funky conenction info, since we don't expect
+        # to connect.
+        return DirectoryService(u"ldap://cretin/", u"o=plugh")
+
+
+    def fieldNameMap(self, service):
         """
         Create a mapping from field names to LDAP attribute names.
         The attribute names returned here are not real LDAP attribute names,
@@ -48,12 +54,22 @@
         return dict([(c, c.name) for c in service.fieldName.iterconstants()])
 
 
+    def recordTypeMap(self, service):
+        """
+        Create a mapping from record types to LDAP object class names.
+        The object class names returned here are not real LDAP object class
+        names, but we don't care for these tests, since we're not actually
+        connecting to LDAP.
+        """
+        return dict([(c, c.name) for c in service.recordType.iterconstants()])
+
+
     def test_queryStringFromMatchExpression_matchTypes(self):
         """
         Match expressions with each match type produces the correct
         operator=value string.
         """
-        service = DirectoryService()
+        service = self.service()
 
         for matchType, expected in (
             (MatchType.equals, u"=xyzzy"),
@@ -70,10 +86,11 @@
                 matchType=matchType
             )
             queryString = ldapQueryStringFromMatchExpression(
-                expression, self.attrMap(service)
+                expression,
+                self.fieldNameMap(service), self.recordTypeMap(service),
             )
             expected = u"({attribute}{expected})".format(
-                attribute="shortNames", expected=expected
+                attribute=u"shortNames", expected=expected
             )
             self.assertEquals(queryString, expected)
 
@@ -82,17 +99,18 @@
         """
         Match expression with the C{NOT} flag adds the C{!} operator.
         """
-        service = DirectoryService()
+        service = self.service()
 
         expression = MatchExpression(
             service.fieldName.shortNames, u"xyzzy",
             flags=MatchFlags.NOT
         )
         queryString = ldapQueryStringFromMatchExpression(
-            expression, self.attrMap(service)
+            expression,
+            self.fieldNameMap(service), self.recordTypeMap(service),
         )
         expected = u"(!{attribute}=xyzzy)".format(
-            attribute="shortNames",
+            attribute=u"shortNames",
         )
         self.assertEquals(queryString, expected)
 
@@ -102,17 +120,18 @@
         Match expression with the C{caseInsensitive} flag adds the C{??????}
         operator.
         """
-        service = DirectoryService()
+        service = self.service()
 
         expression = MatchExpression(
             service.fieldName.shortNames, u"xyzzy",
             flags=MatchFlags.caseInsensitive
         )
         queryString = ldapQueryStringFromMatchExpression(
-            expression, self.attrMap(service)
+            expression,
+            self.fieldNameMap(service), self.recordTypeMap(service),
         )
         expected = u"???????({attribute}=xyzzy)".format(
-            attribute="shortNames",
+            attribute=u"shortNames",
         )
         self.assertEquals(queryString, expected)
 
@@ -126,17 +145,18 @@
         """
         Special characters are quoted properly.
         """
-        service = DirectoryService()
+        service = self.service()
 
         expression = MatchExpression(
             service.fieldName.fullNames,
             u"\\xyzzy: a/b/(c)* ~~ >=< ~~ &| \0!!"
         )
         queryString = ldapQueryStringFromMatchExpression(
-            expression, self.attrMap(service)
+            expression,
+            self.fieldNameMap(service), self.recordTypeMap(service),
         )
         expected = u"({attribute}={expected})".format(
-            attribute="fullNames",
+            attribute=u"fullNames",
             expected=(
                 u"\\5Cxyzzy: a\\2Fb\\2F\\28c\\29\\2A "
                 "\\7E\\7E \\3E\\3D\\3C \\7E\\7E \\26\\7C \\00!!"
@@ -149,7 +169,7 @@
         """
         Unknown expression.
         """
-        service = DirectoryService()
+        service = self.service()
 
         expression = MatchExpression(
             object(), u"xyzzy",
@@ -158,7 +178,8 @@
         self.assertRaises(
             QueryNotSupportedError,
             ldapQueryStringFromMatchExpression,
-            expression, self.attrMap(service)
+            expression,
+            self.fieldNameMap(service), self.recordTypeMap(service),
         )
 
 
@@ -166,7 +187,7 @@
         """
         Unknown expression.
         """
-        service = DirectoryService()
+        service = self.service()
 
         expression = MatchExpression(
             service.fieldName.shortNames, u"xyzzy",
@@ -176,7 +197,8 @@
         self.assertRaises(
             QueryNotSupportedError,
             ldapQueryStringFromMatchExpression,
-            expression, self.attrMap(service)
+            expression,
+            self.fieldNameMap(service), self.recordTypeMap(service),
         )
 
 
@@ -192,7 +214,7 @@
         The Operand shouldn't make any difference here, so we test AND and OR,
         expecting the same result.
         """
-        service = DirectoryService()
+        service = self.service()
 
         for operand in (Operand.AND, Operand.OR):
             matchExpression = MatchExpression(
@@ -203,11 +225,13 @@
                 operand
             )
             queryString = queryFunction(
-                compoundExpression, self.attrMap(service)
+                compoundExpression,
+                self.fieldNameMap(service), self.recordTypeMap(service),
             )
             expected = u"{match}".format(
                 match=ldapQueryStringFromMatchExpression(
-                    matchExpression, self.attrMap(service)
+                    matchExpression,
+                    self.fieldNameMap(service), self.recordTypeMap(service),
                 )
             )
             self.assertEquals(queryString, expected)
@@ -221,7 +245,7 @@
 
         The sub-expressions should be grouped with the given operand.
         """
-        service = DirectoryService()
+        service = self.service()
 
         for (operand, token) in ((Operand.AND, u"&"), (Operand.OR, u"|")):
             matchExpression1 = MatchExpression(
@@ -235,15 +259,18 @@
                 operand
             )
             queryString = queryFunction(
-                compoundExpression, self.attrMap(service)
+                compoundExpression,
+                self.fieldNameMap(service), self.recordTypeMap(service),
             )
             expected = u"({op}{match1}{match2})".format(
                 op=token,
                 match1=ldapQueryStringFromMatchExpression(
-                    matchExpression1, self.attrMap(service)
+                    matchExpression1,
+                    self.fieldNameMap(service), self.recordTypeMap(service),
                 ),
                 match2=ldapQueryStringFromMatchExpression(
-                    matchExpression2, self.attrMap(service)
+                    matchExpression2,
+                    self.fieldNameMap(service), self.recordTypeMap(service),
                 ),
             )
             self.assertEquals(queryString, expected)
@@ -253,16 +280,18 @@
         """
         Match expression.
         """
-        service = DirectoryService()
+        service = self.service()
 
         matchExpression = MatchExpression(
             service.fieldName.shortNames, u"xyzzy"
         )
         queryString = ldapQueryStringFromExpression(
-            matchExpression, self.attrMap(service)
+            matchExpression,
+            self.fieldNameMap(service), self.recordTypeMap(service),
         )
         expected = ldapQueryStringFromMatchExpression(
-            matchExpression, self.attrMap(service)
+            matchExpression,
+            self.fieldNameMap(service), self.recordTypeMap(service),
         )
         self.assertEquals(queryString, expected)
 
@@ -283,10 +312,10 @@
         """
         Unknown expression.
         """
-        service = DirectoryService()
+        service = self.service()
 
         self.assertRaises(
             QueryNotSupportedError,
             ldapQueryStringFromExpression,
-            object(), self.attrMap(service)
+            object(), self.fieldNameMap(service), self.recordTypeMap(service)
         )

Modified: twext/trunk/twext/who/test/test_directory.py
===================================================================
--- twext/trunk/twext/who/test/test_directory.py	2014-01-14 00:20:20 UTC (rev 12330)
+++ twext/trunk/twext/who/test/test_directory.py	2014-01-14 00:38:59 UTC (rev 12331)
@@ -227,8 +227,8 @@
     @inlineCallbacks
     def test_recordsFromExpression_emptyExpression(self):
         """
-        L{DirectoryService.recordsFromExpression} with an unknown expression
-        type and an empty L{CompoundExpression} returns an empty result.
+        L{DirectoryService.recordsFromExpression} with an empty
+        L{CompoundExpression} returns an empty result.
         """
         service = self.service()
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140312/f30cd6e0/attachment.html>


More information about the calendarserver-changes mailing list