Hello community,

here is the log from the commit of package python-slapdsock for 
openSUSE:Factory checked in at 2017-11-12 18:03:42
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-slapdsock (Old)
 and      /work/SRC/openSUSE:Factory/.python-slapdsock.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-slapdsock"

Sun Nov 12 18:03:42 2017 rev:6 rq:540771 version:0.7.6

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-slapdsock/python-slapdsock.changes        
2017-09-11 16:17:51.906208778 +0200
+++ /work/SRC/openSUSE:Factory/.python-slapdsock.new/python-slapdsock.changes   
2017-11-12 18:03:43.773796014 +0100
@@ -1,0 +2,7 @@
+Sat Nov 11 17:56:58 UTC 2017 - [email protected]
+
+- update to upstream release 0.7.6
+  * more message classes
+  * minor bug fixes
+
+-------------------------------------------------------------------

Old:
----
  slapdsock-0.6.0.tar.gz
  slapdsock-0.6.0.tar.gz.asc

New:
----
  slapdsock-0.7.6.tar.gz
  slapdsock-0.7.6.tar.gz.asc

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-slapdsock.spec ++++++
--- /var/tmp/diff_new_pack.c39L1R/_old  2017-11-12 18:03:45.725724916 +0100
+++ /var/tmp/diff_new_pack.c39L1R/_new  2017-11-12 18:03:45.725724916 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           python-slapdsock
-Version:        0.6.0
+Version:        0.7.6
 Release:        0
 Summary:        Python module for slapd-sock listeners
 License:        Apache-2.0

++++++ slapdsock-0.6.0.tar.gz -> slapdsock-0.7.6.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/slapdsock-0.6.0/PKG-INFO new/slapdsock-0.7.6/PKG-INFO
--- old/slapdsock-0.6.0/PKG-INFO        2017-09-06 10:44:43.000000000 +0200
+++ new/slapdsock-0.7.6/PKG-INFO        2017-11-11 18:54:29.000000000 +0100
@@ -1,11 +1,12 @@
 Metadata-Version: 1.1
 Name: slapdsock
-Version: 0.6.0
+Version: 0.7.6
 Summary: Module package for back-sock listeners for OpenLDAP
 Home-page: https://www.stroeder.com/slapdsock.html
 Author: Michael Stroeder
 Author-email: [email protected]
 License: Apache License, Version 2.0
+Description-Content-Type: UNKNOWN
 Description: Module package for implementing back-sock listeners
         for the OpenLDAP server either working as
         full backend or overlay.
Binary files old/slapdsock-0.6.0/examples/openldap/accesslog/data.mdb and 
new/slapdsock-0.7.6/examples/openldap/accesslog/data.mdb differ
Binary files old/slapdsock-0.6.0/examples/openldap/accesslog/lock.mdb and 
new/slapdsock-0.7.6/examples/openldap/accesslog/lock.mdb differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/slapdsock-0.6.0/examples/openldap/realdb.conf 
new/slapdsock-0.7.6/examples/openldap/realdb.conf
--- old/slapdsock-0.6.0/examples/openldap/realdb.conf   2017-09-06 
10:44:25.000000000 +0200
+++ new/slapdsock-0.7.6/examples/openldap/realdb.conf   2017-11-06 
23:26:57.000000000 +0100
@@ -16,13 +16,9 @@
 
 overlay sock
 extensions binddn peername ssf connid
-socketpath /tmp/modify-listener
-sockops modify
-
-overlay sock
-extensions binddn peername ssf connid
-socketpath /tmp/bind-listener
-sockops bind
+socketpath /tmp/noop-listener
+#sockdnpat "^uid=[a-z0-9]+,ou=data,dc=example,dc=org$"
+sockops compare extended
 
 access to
   dn.subtree="ou=data,dc=example,dc=org"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/slapdsock-0.6.0/examples/passmod.py 
new/slapdsock-0.7.6/examples/passmod.py
--- old/slapdsock-0.6.0/examples/passmod.py     2017-09-06 10:44:25.000000000 
+0200
+++ new/slapdsock-0.7.6/examples/passmod.py     2017-09-12 14:23:19.000000000 
+0200
@@ -123,6 +123,18 @@
 # Classes and functions
 #-----------------------------------------------------------------------
 
+def unicode_pwd(password):
+    """
+    returns password or random generated password as properly encoded
+    'unicodePwd' value for MS AD
+
+    see also:
+    https://msdn.microsoft.com/en-us/library/cc223248.aspx
+    
https://support.microsoft.com/en-us/help/269190/how-to-change-a-windows-active-directory-and-lds-user-password-through-ldap
+    """
+    return u'"{}"'.format(password).encode('utf-16-le')
+
+
 class DictQueue(Queue.Queue):
     """
     modified Queue class which internally stores items in a dict
@@ -146,14 +158,12 @@
     """
     Thread class for the password synchronization worker
     """
-    interval = 1.0
+    passwd_update_delay = 1.0
     source_id_attr = 'uid'
     target_filter_format = '({0}={1})'
     target_id_attr = 'uid'
     target_password_attr = 'userPassword'
     target_password_encoding = 'utf-8'
-    # MS AD
-    #target_password_attr = 'unicodePwd'
 
     def __init__(
             self,
@@ -173,19 +183,56 @@
         self._queue = queue
         threading.Thread.__init__(self, 
name=self.__class__.__module__+self.__class__.__name__)
         LocalLDAPConn.__init__(self, self.logger)
-        # open connection to target LDAP server
-        self.target_conn = MyLDAPObject(
-            target_ldap_url.initializeUrl(),
-            trace_level=PYLDAP_TRACELEVEL,
-            trace_file=LoggerFileobj(self.logger, logging.DEBUG),
-            retry_max=LDAP_MAXRETRYCOUNT,
-            retry_delay=LDAP_RETRYDELAY,
-            who=target_ldap_url.who or '',
-            cred=target_ldap_url.cred or '',
-            cache_time=LDAP_CACHE_TTL,
+        self._target_conn = None
+        self._target_conn_lock = ldap.LDAPLock(
+            desc='target_conn() in %s' % (repr(self.__class__))
         )
         # end of PWSyncWorker.__init__()
 
+    def target_conn(self):
+        """
+        open and cache target connection
+        """
+        if isinstance(self._target_conn, MyLDAPObject):
+            self.logger.debug(
+                'Existing LDAP connection to %s (%s)',
+                repr(self._target_conn._uri),
+                repr(self._target_conn),
+            )
+            return self._target_conn
+        try:
+            self._target_conn_lock.acquire()
+            try:
+                self._target_conn = MyLDAPObject(
+                    self._target_ldap_url.initializeUrl(),
+                    trace_level=PYLDAP_TRACELEVEL,
+                    trace_file=LoggerFileobj(self.logger, logging.DEBUG),
+                    retry_max=LDAP_MAXRETRYCOUNT,
+                    retry_delay=LDAP_RETRYDELAY,
+                    who=self._target_ldap_url.who or '',
+                    cred=self._target_ldap_url.cred or '',
+                    cache_time=LDAP_CACHE_TTL,
+                )
+            except ldap.LDAPError, ldap_error:
+                self._target_conn = None
+                self.logger.error(
+                    'LDAPError during connecting to %s: %s',
+                    repr(self.ldapi_uri),
+                    str(ldap_error),
+                )
+                raise ldap_error
+            else:
+                self._target_conn.authz_id = self._target_conn.whoami_s()
+                self.logger.info(
+                    'Successfully bound to %s as %s (%s)',
+                    repr(self.ldapi_uri),
+                    repr(self._target_conn.authz_id),
+                    repr(self._target_conn),
+                )
+        finally:
+            self._target_conn_lock.release()
+        return self._target_conn # get_ldapi_conn()
+
     def _check_password(self, user_dn, new_passwd):
         password_correct = False
         self.logger.debug('Check password of %r', user_dn)
@@ -205,7 +252,6 @@
                     cache_time=LDAP_CACHE_TTL,
                 )
             except ldap.INVALID_CREDENTIALS:
-                self.logger.warn('Ignoring wrong password for %r', user_dn)
                 password_correct = False
             else:
                 password_correct = True
@@ -229,7 +275,7 @@
             )
             return None
         self.logger.debug('Extracted %s=%r from source_dn=%r', 
self.source_id_attr, uid, source_dn)
-        target_conn = self.target_conn
+        target_conn = self.target_conn()
         target_filter = self.target_filter_format.format(self.target_id_attr, 
uid)
         ldap_result = target_conn.search_ext_s(
             self._target_ldap_url.dn,
@@ -246,11 +292,6 @@
         ]
         self.logger.debug('ldap_result=%r', ldap_result)
         if len(ldap_result) != 1:
-            self.logger.warn(
-                'No unique ID found with %r => ignore password change of %r',
-                target_filter,
-                source_dn,
-            )
             return None
         target_id = ldap_result[0][0]
         return target_id # end of PWSyncWorker.get_target_id()
@@ -259,13 +300,18 @@
         """
         encode argument password for target system
         """
-        return password.decode('utf-8').encode(self.target_password_encoding)
+        pwu = password.decode('utf-8')
+        if self.target_password_attr.lower() == 'unicodepwd':
+            result = unicode_pwd(pwu)
+        else:
+            result = pwu.encode(self.target_password_encoding)
+        return result
 
     def update_target_password(self, target_id, old_passwd, new_passwd, 
req_time):
         """
         write new password to target
         """
-        target_conn = self.target_conn
+        target_conn = self.target_conn()
         modlist = [(
             ldap.MOD_REPLACE,
             self.target_password_attr,
@@ -290,13 +336,27 @@
                 ldap_strf_secs(req_time),
             )
             try:
+                sleep_time = max(
+                    0,
+                    time.time()-req_time+self.passwd_update_delay
+                )
+                self.logger.debug(
+                    'Deferring syncing password for %r for %f secs',
+                    user_dn,
+                    sleep_time,
+                )
+                time.sleep(sleep_time)
                 if not self._check_password(user_dn, new_passwd):
                     # simply ignore wrong passwords
-                    self._queue.put((user_dn, (old_passwd, new_passwd, 
req_time)))
+                    self.logger.warn('Ignoring wrong password for %r', user_dn)
                     continue
                 target_id = self.get_target_id(user_dn)
                 if target_id is None:
                     # simply ignore non-existent targets
+                    self.logger.warn(
+                        'No target ID found for %r => ignore password change',
+                        user_dn,
+                    )
                     continue
                 self.logger.debug('Try to sync password for %r to %r', 
user_dn, target_id)
                 self.update_target_password(target_id, old_passwd, new_passwd, 
req_time)
@@ -306,7 +366,6 @@
                     user_dn,
                     exc_info=True,
                 )
-                #self._queue.put((user_dn, (old_passwd, new_passwd, req_time)))
             else:
                 self.logger.info('Synced password for %r to %r', user_dn, 
target_id)
             self._queue.task_done()
@@ -481,12 +540,16 @@
         socket_path = sys.argv[1]
         local_ldap_uri = sys.argv[2]
         target_ldap_url = sys.argv[3]
+        target_password_filename = sys.argv[4]
     except IndexError:
         my_logger.error('Not enough arguments => abort')
         sys.exit(1)
 
     local_ldap_uri_obj = MyLDAPUrl(local_ldap_uri)
     target_ldap_url_obj = MyLDAPUrl(target_ldap_url)
+    # read target password from file
+    with open(target_password_filename, 'rb') as target_password_file:
+        target_ldap_url_obj.cred = target_password_file.read()
 
     # initialize password sync consumer thread
     pwsync_worker = PWSyncWorker(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/slapdsock-0.6.0/examples/test.py 
new/slapdsock-0.7.6/examples/test.py
--- old/slapdsock-0.6.0/examples/test.py        1970-01-01 01:00:00.000000000 
+0100
+++ new/slapdsock-0.7.6/examples/test.py        2017-09-04 17:03:57.000000000 
+0200
@@ -0,0 +1,7 @@
+import ldap
+
+l = 
ldap.initialize('ldapi://%2Fhome%2Fmichael%2FProj%2Fpython-slapdsockd%2Fexamples%2Fopenldap%2Fldapi')
+
+l.sasl_external_bind_s()
+
+l.passwd_s('uid=test2,ou=data,dc=example,dc=org', None, '\x00')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/slapdsock-0.6.0/slapdsock/handler.py 
new/slapdsock-0.7.6/slapdsock/handler.py
--- old/slapdsock-0.6.0/slapdsock/handler.py    2017-09-06 10:44:25.000000000 
+0200
+++ new/slapdsock-0.7.6/slapdsock/handler.py    2017-11-10 14:20:43.000000000 
+0100
@@ -17,14 +17,20 @@
 #-----------------------------------------------------------------------
 
 # from Python's standard lib
-import sys, pwd, struct
+import sys
+import pwd
+import struct
 import time
-import socket, SocketServer
-import logging, inspect
+import socket
+import SocketServer
+import logging
+import inspect
+import datetime
 
 # internal import from slapsock
 import slapdsock.message
 from slapdsock.message import ENTRYResponse, RESULTResponse, 
InternalErrorResponse
+from slapdsock.ldaphelper import ldap_datetime_str
 
 #-----------------------------------------------------------------------
 # Constants
@@ -110,6 +116,9 @@
 
     def __init__(self, *args, **kwargs):
         self._logged_vars = set()
+        # We need current time in GeneralizedTime syntax later
+        self.now_dt = datetime.datetime.utcnow()
+        self.now_str = ldap_datetime_str(self.now_dt)
         SocketServer.BaseRequestHandler.__init__(self, *args, **kwargs)
 
     def _get_peer_cred(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/slapdsock-0.6.0/slapdsock/ldaphelper.py 
new/slapdsock-0.7.6/slapdsock/ldaphelper.py
--- old/slapdsock-0.6.0/slapdsock/ldaphelper.py 2017-09-06 10:44:25.000000000 
+0200
+++ new/slapdsock-0.7.6/slapdsock/ldaphelper.py 2017-11-10 17:04:48.000000000 
+0100
@@ -431,6 +431,7 @@
     ldapi_authz_id = ''
     ldap_retry_max = 4
     ldap_retry_delay = 1.0
+    ldap_timeout = LDAP_TIMEOUT
     ldap_cache_ttl = 0.0
     ldap_trace_level = 0
 
@@ -480,6 +481,7 @@
                     trace_file=self._logger_fileobj,
                     retry_max=self.ldap_retry_max,
                     retry_delay=self.ldap_retry_delay,
+                    timeout=self.ldap_timeout,
                     cache_time=self.ldap_cache_ttl,
                 )
                 self._ldapi_conn.sasl_external_bind_s(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/slapdsock-0.6.0/slapdsock/message.py 
new/slapdsock-0.7.6/slapdsock/message.py
--- old/slapdsock-0.6.0/slapdsock/message.py    2017-09-06 10:44:25.000000000 
+0200
+++ new/slapdsock-0.7.6/slapdsock/message.py    2017-11-11 18:52:55.000000000 
+0100
@@ -7,6 +7,7 @@
 """
 
 __all__ = [
+    'CONTINUE_RESPONSE',
     'ListFile',
     'SockRequest',
     'ADDRequest',
@@ -22,6 +23,14 @@
     'SockResponse',
     'RESULTResponse',
     'ENTRYResponse',
+    'CompareFalseResponse',
+    'CompareTrueResponse',
+    'NoSuchObjectResponse',
+    'InvalidCredentialsResponse',
+    'UnwillingToPerformResponse',
+    'SuccessResponse',
+    'InternalErrorResponse',
+    'InvalidAttributeSyntaxResponse',
 ]
 
 #-----------------------------------------------------------------------
@@ -45,6 +54,13 @@
 from slapdsock.ldaphelper import RESULT_CODE
 
 #-----------------------------------------------------------------------
+# Constants
+#-----------------------------------------------------------------------
+
+CONTINUE_RESPONSE = 'CONTINUE\n'
+
+
+#-----------------------------------------------------------------------
 # Classes and functions
 #-----------------------------------------------------------------------
 
@@ -66,7 +82,6 @@
 
 
 class ListFile(object):
-
     """
     File-like object with readline method returning lines from a list
     of strings
@@ -193,8 +208,9 @@
 
     def _get_attrs(self):
         SockRequest._get_attrs(self)
-        self.dn, self.entry = self._parse_ldif(
+        dn, self.entry = self._parse_ldif(
             self._linecount, max_entries=1)[0]
+        self.dn = dn.decode('utf-8')
 
 
 class BINDRequest(SockRequest):
@@ -280,7 +296,7 @@
         SockRequest._get_attrs(self)
 
 
-class COMPARERequest(SockRequest):
+class COMPARERequest(ADDRequest):
 
     """
     COMPARE
@@ -297,15 +313,28 @@
         'ssf': int,
         'connid': int,
         'suffix': ldap_str,
-        'dn': ldap_str,
     }
     cache_key_attrs = (
         'binddn',
         'ssf',
         'suffix',
         'dn',
+        'atype',
+        'avalue',
     )
 
+    def _get_attrs(self):
+        SockRequest._get_attrs(self)
+        self.dn, entry = self._parse_ldif(self._linecount, max_entries=1)[0]
+        assert len(entry) == 1, ValueError(
+            'Only one assertion type allowed but, was: %r' % entry
+        )
+        self.atype = entry.keys()[0].decode('utf-8')
+        assert len(entry[self.atype]) == 1, ValueError(
+            'Only one assertion value allowed, but was: %r' % entry[self.atype]
+        )
+        self.avalue = entry[self.atype][0]
+
 
 class DELETERequest(SockRequest):
 
@@ -355,8 +384,9 @@
 
     def _get_attrs(self):
         SockRequest._get_attrs(self)
-        self.dn, self.modops, _ = self._parse_ldif(
+        dn, self.modops, _ = self._parse_ldif(
             self._linecount, max_entries=1)[0]
+        self.dn = dn.decode('utf-8')
 
 
 class MODRDNRequest(SockRequest):
@@ -559,8 +589,7 @@
     """
 
     def __init__(self, msgid, dn, entry):
-        resp_lines = [
-        ]
+        resp_lines = []
         self._dn = dn
         self._entry = entry
         SockResponse.__init__(self, 'ENTRY', resp_lines)
@@ -577,31 +606,135 @@
         ))
 
 
+class SuccessResponse(RESULTResponse):
+    """
+    Convenience wrapper class for returning success(0)
+    """
+
+    def __init__(self, msgid, info=None):
+        RESULTResponse.__init__(
+            self,
+            msgid,
+            code=0,
+            matched=None,
+            info=info
+        )
+
+
+class CompareFalseResponse(RESULTResponse):
+    """
+    Convenience wrapper class for returning compareFalse(5)
+    """
+
+    def __init__(self, msgid, info=None):
+        RESULTResponse.__init__(
+            self,
+            msgid,
+            code=5,
+            matched=None,
+            info=info
+        )
+
+
+class CompareTrueResponse(RESULTResponse):
+    """
+    Convenience wrapper class for returning compareTrue(6)
+    """
+
+    def __init__(self, msgid, info=None):
+        RESULTResponse.__init__(
+            self,
+            msgid,
+            code=6,
+            matched=None,
+            info=info
+        )
+
+
+class InvalidAttributeSyntaxResponse(RESULTResponse):
+    """
+    Convenience wrapper class for returning invalidAttributeSyntax(21)
+    """
+
+    def __init__(self, msgid, info=None):
+        RESULTResponse.__init__(
+            self,
+            msgid,
+            code=21,
+            matched=None,
+            info=info
+        )
+
+
+class ConstraintViolationResponse(RESULTResponse):
+    """
+    Convenience wrapper class for returning constraintViolation(19)
+    """
+
+    def __init__(self, msgid, info=None):
+        RESULTResponse.__init__(
+            self,
+            msgid,
+            code=19,
+            matched=None,
+            info=info
+        )
+
+
+class NoSuchObjectResponse(RESULTResponse):
+    """
+    Convenience wrapper class for returning noSuchObject(32)
+    """
+
+    def __init__(self, msgid, info=None, matched=None):
+        RESULTResponse.__init__(
+            self,
+            msgid,
+            code=32,
+            matched=None,
+            info=info
+        )
+
+
 class InvalidCredentialsResponse(RESULTResponse):
     """
-    Convenience wrapper class for returning invalidCredentials
+    Convenience wrapper class for returning invalidCredentials(49)
     """
 
     def __init__(self, msgid, info=None):
         RESULTResponse.__init__(
             self,
             msgid,
-            code='invalidCredentials',
+            code=49,
             matched=None,
             info=info
         )
 
 
-class InternalErrorResponse(RESULTResponse):
+class UnwillingToPerformResponse(RESULTResponse):
     """
-    Convenience wrapper class for returning unwillingToPerform and
-    diagnostic message 'internal error'
+    Convenience wrapper class for returning unwillingToPerform(53)
     """
 
     def __init__(self, msgid, info=None):
         RESULTResponse.__init__(
             self,
             msgid,
-            code='unwillingToPerform',
+            code=53,
+            matched=None,
+            info=info
+        )
+
+
+class InternalErrorResponse(UnwillingToPerformResponse):
+    """
+    Convenience wrapper class for returning unwillingToPerform(53) and
+    diagnostic message 'internal error'
+    """
+
+    def __init__(self, msgid, info=None):
+        UnwillingToPerformResponse.__init__(
+            self,
+            msgid,
             info=info or 'internal error'
         )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/slapdsock-0.6.0/slapdsock/pkginfo.py 
new/slapdsock-0.7.6/slapdsock/pkginfo.py
--- old/slapdsock-0.6.0/slapdsock/pkginfo.py    2017-09-06 10:44:25.000000000 
+0200
+++ new/slapdsock-0.7.6/slapdsock/pkginfo.py    2017-11-11 18:54:17.000000000 
+0100
@@ -2,6 +2,6 @@
 """
 meta attributes for packaging which does not import any dependencies
 """
-__version__ = '0.6.0'
+__version__ = '0.7.6'
 __author__ = u'Michael Ströder <[email protected]>'
 __license__ = 'Apache License, Version 2.0'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/slapdsock-0.6.0/slapdsock/test.py 
new/slapdsock-0.7.6/slapdsock/test.py
--- old/slapdsock-0.6.0/slapdsock/test.py       1970-01-01 01:00:00.000000000 
+0100
+++ new/slapdsock-0.7.6/slapdsock/test.py       2017-11-09 09:13:52.000000000 
+0100
@@ -0,0 +1,66 @@
+# -*- coding: utf-8 -*-
+"""
+aedir.test - base classes for unit tests
+"""
+
+# from Python's standard lib
+import logging
+import os
+
+# from python-ldap
+import slapdtest
+
+__all__ = [
+    'SlapdObject',
+    'SlapdSockTest',
+]
+
+
+# a template string for generating simple slapd.conf file
+SLAPD_CONF_TEMPLATE = r"""
+serverID %(serverid)s
+moduleload back_%(database)s
+include "%(schema_include)s"
+loglevel %(loglevel)s
+allow bind_v2
+
+authz-regexp
+  
"gidnumber=%(root_gid)s\\+uidnumber=%(root_uid)s,cn=peercred,cn=external,cn=auth"
+  "%(rootdn)s"
+
+database %(database)s
+directory "%(directory)s"
+suffix "%(suffix)s"
+rootdn "%(rootdn)s"
+rootpw "%(rootpw)s"
+"""
+
+
+class SlapdObject(slapdtest.SlapdObject):
+    """
+    run test slapd process
+    """
+    database = 'sock'
+    slapd_conf_template = SLAPD_CONF_TEMPLATE
+    suffix = 'dc=slapdsock,dc=stroeder,dc=com'
+
+
+class SlapdSockTest(slapdtest.SlapdTestCase):
+    """
+    test class which initializes an slapd with back-sock
+    """
+
+    server_class = SlapdObject
+    slapdsock_server_class = 
+    slapdsock_handler_class = 
+    init_ldif_file = None
+
+    @classmethod
+    def setUpClass(cls):
+        cls.server = cls.server_class()
+        cls.server.start()
+        cls.server = cls.server
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.server.stop()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/slapdsock-0.6.0/slapdsock.egg-info/PKG-INFO 
new/slapdsock-0.7.6/slapdsock.egg-info/PKG-INFO
--- old/slapdsock-0.6.0/slapdsock.egg-info/PKG-INFO     2017-09-06 
10:44:43.000000000 +0200
+++ new/slapdsock-0.7.6/slapdsock.egg-info/PKG-INFO     2017-11-11 
18:54:29.000000000 +0100
@@ -1,11 +1,12 @@
 Metadata-Version: 1.1
 Name: slapdsock
-Version: 0.6.0
+Version: 0.7.6
 Summary: Module package for back-sock listeners for OpenLDAP
 Home-page: https://www.stroeder.com/slapdsock.html
 Author: Michael Stroeder
 Author-email: [email protected]
 License: Apache License, Version 2.0
+Description-Content-Type: UNKNOWN
 Description: Module package for implementing back-sock listeners
         for the OpenLDAP server either working as
         full backend or overlay.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/slapdsock-0.6.0/slapdsock.egg-info/SOURCES.txt 
new/slapdsock-0.7.6/slapdsock.egg-info/SOURCES.txt
--- old/slapdsock-0.6.0/slapdsock.egg-info/SOURCES.txt  2017-09-06 
10:44:43.000000000 +0200
+++ new/slapdsock-0.7.6/slapdsock.egg-info/SOURCES.txt  2017-11-11 
18:54:29.000000000 +0100
@@ -7,12 +7,15 @@
 examples/noop_logger.py
 examples/passmod.py
 examples/simple_bind_demo.py
+examples/test.py
 examples/openldap/realdb.conf
 examples/openldap/realdb.ldif
 examples/openldap/slapd.conf
 examples/openldap/sockdb.conf
 examples/openldap/start-slapd.sh
 examples/openldap/accesslog/.gitignore
+examples/openldap/accesslog/data.mdb
+examples/openldap/accesslog/lock.mdb
 examples/openldap/realdb/.gitignore
 slapdsock/.gitignore
 slapdsock/__init__.py
@@ -23,6 +26,7 @@
 slapdsock/message.py
 slapdsock/pkginfo.py
 slapdsock/service.py
+slapdsock/test.py
 slapdsock.egg-info/PKG-INFO
 slapdsock.egg-info/SOURCES.txt
 slapdsock.egg-info/dependency_links.txt
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/slapdsock-0.6.0/tests/t_message.py 
new/slapdsock-0.7.6/tests/t_message.py
--- old/slapdsock-0.6.0/tests/t_message.py      2017-09-06 10:44:25.000000000 
+0200
+++ new/slapdsock-0.7.6/tests/t_message.py      2017-11-06 23:25:07.000000000 
+0100
@@ -17,7 +17,7 @@
 
 # from python-slapdsock
 from slapdsock.message import ldap_str, ldap_attrs
-from slapdsock.message import BINDRequest, MODIFYRequest, EXTENDEDRequest, 
RESULTResponse
+from slapdsock.message import BINDRequest, COMPARERequest, MODIFYRequest, 
EXTENDEDRequest, RESULTResponse
 
 #-----------------------------------------------------------------------
 # Test slapdsock.message.BINDRequest
@@ -87,6 +87,30 @@
 
 """
 
+compare_message_simple = """COMPARE
+msgid: 129
+binddn: cn=root,ou=realdb,dc=example,dc=org
+peername: PATH=/tmp/slapd_sockd/examples/openldap/ldapi
+ssf: 71
+connid: 1004
+suffix: ou=realdb,dc=example,dc=org
+dn: [email protected],ou=Testing,dc=example,dc=org
+mail: [email protected]
+
+"""
+
+compare_message_utf8 = """COMPARE
+msgid: 129
+binddn: cn=root,ou=realdb,dc=example,dc=org
+peername: PATH=/tmp/slapd_sockd/examples/openldap/ldapi
+ssf: 71
+connid: 1004
+suffix: ou=realdb,dc=example,dc=org
+dn: cn=Michael Str\xc3\xb6der,ou=Testing,dc=example,dc=org
+cn:: TWljaGFlbCBTdHLDtmRlcg==
+
+"""
+
 modify_message_userpassword = """MODIFY
 msgid: 2
 binddn: cn=root,ou=realdb,dc=example,dc=org
@@ -244,6 +268,36 @@
         self.assertEquals(req.cred, '\x00\x01\x00\n\x01\x00\x01\x00\x01')
 
 
+class TestCOMPARERequest(TestRequestMessage):
+    """
+    Test various cases for COMPARERequest
+    """
+
+    def test_simple(self):
+        req = COMPARERequest(self.prepare_request_msg(compare_message_simple))
+        self.assertEquals(req.reqtype, u'COMPARE')
+        self.assertEquals(req.msgid, 129)
+        self.assertEquals(req.binddn, u'cn=root,ou=realdb,dc=example,dc=org')
+        self.assertEquals(req.peername, 
u'PATH=/tmp/slapd_sockd/examples/openldap/ldapi')
+        self.assertEquals(req.ssf, 71)
+        self.assertEquals(req.connid, 1004)
+        self.assertEquals(req.dn, 
u'[email protected],ou=Testing,dc=example,dc=org')
+        self.assertEquals(req.atype, u'mail')
+        self.assertEquals(req.avalue, '[email protected]')
+
+    def test_utf8(self):
+        req = COMPARERequest(self.prepare_request_msg(compare_message_utf8))
+        self.assertEquals(req.reqtype, u'COMPARE')
+        self.assertEquals(req.msgid, 129)
+        self.assertEquals(req.binddn, u'cn=root,ou=realdb,dc=example,dc=org')
+        self.assertEquals(req.peername, 
u'PATH=/tmp/slapd_sockd/examples/openldap/ldapi')
+        self.assertEquals(req.ssf, 71)
+        self.assertEquals(req.connid, 1004)
+        self.assertEquals(req.dn, 'cn=Michael 
Str\xc3\xb6der,ou=Testing,dc=example,dc=org')
+        self.assertEquals(req.atype, u'cn')
+        self.assertEquals(req.avalue, 'Michael Str\xc3\xb6der')
+
+
 class TestMODIFYRequest(TestRequestMessage):
     """
     Test various cases for MODIFYRequest


Reply via email to