f5000e
From fc0ca25b9f143083528cc5f87dc89fe69baf38fd Mon Sep 17 00:00:00 2001
f5000e
From: Simon Pichugin <spichugi@redhat.com>
f5000e
Date: Thu, 28 Apr 2016 11:49:24 +0200
f5000e
Subject: [PATCH 93/93] Ticket 48808 - Add test case
f5000e
f5000e
Description: Add test case for paged results search returns the blank
f5000e
list of entries issue.
f5000e
f5000e
Bug description: After series of actions, paged result search that
f5000e
should returns list of entries returns blank list of entries. It is
f5000e
hardly reproducible manually, but it is easy to reproduce with python
f5000e
automation.
f5000e
f5000e
https://fedorahosted.org/389/ticket/48808
f5000e
f5000e
Reviewed by: nhosoi and wbrown (Thanks!)
f5000e
f5000e
(cherry picked from commit 91f3e592713ea58602412ed773a497583f2ebd6c)
f5000e
(cherry picked from commit 99b5048b09e64cea6f8bf5e7d524679960ce0a44)
f5000e
---
f5000e
 dirsrvtests/tests/tickets/ticket48808_test.py | 337 ++++++++++++++++++++++++++
f5000e
 1 file changed, 337 insertions(+)
f5000e
 create mode 100644 dirsrvtests/tests/tickets/ticket48808_test.py
f5000e
f5000e
diff --git a/dirsrvtests/tests/tickets/ticket48808_test.py b/dirsrvtests/tests/tickets/ticket48808_test.py
f5000e
new file mode 100644
f5000e
index 0000000..3dbceac
f5000e
--- /dev/null
f5000e
+++ b/dirsrvtests/tests/tickets/ticket48808_test.py
f5000e
@@ -0,0 +1,337 @@
f5000e
+import time
f5000e
+import ldap
f5000e
+import logging
f5000e
+import pytest
f5000e
+from random import sample
f5000e
+from ldap.controls import SimplePagedResultsControl
f5000e
+from lib389 import DirSrv, Entry, tools, tasks
f5000e
+from lib389.tools import DirSrvTools
f5000e
+from lib389._constants import *
f5000e
+from lib389.properties import *
f5000e
+from lib389.tasks import *
f5000e
+from lib389.utils import *
f5000e
+
f5000e
+logging.getLogger(__name__).setLevel(logging.DEBUG)
f5000e
+log = logging.getLogger(__name__)
f5000e
+
f5000e
+TEST_USER_NAME = 'simplepaged_test'
f5000e
+TEST_USER_DN = 'uid=%s,%s' % (TEST_USER_NAME, DEFAULT_SUFFIX)
f5000e
+TEST_USER_PWD = 'simplepaged_test'
f5000e
+
f5000e
+
f5000e
+class TopologyStandalone(object):
f5000e
+    def __init__(self, standalone):
f5000e
+        standalone.open()
f5000e
+        self.standalone = standalone
f5000e
+
f5000e
+
f5000e
+@pytest.fixture(scope="module")
f5000e
+def topology(request):
f5000e
+    # Creating standalone instance ...
f5000e
+    standalone = DirSrv(verbose=False)
f5000e
+    args_instance[SER_HOST] = HOST_STANDALONE
f5000e
+    args_instance[SER_PORT] = PORT_STANDALONE
f5000e
+    args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
f5000e
+    args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX
f5000e
+    args_standalone = args_instance.copy()
f5000e
+    standalone.allocate(args_standalone)
f5000e
+    instance_standalone = standalone.exists()
f5000e
+    if instance_standalone:
f5000e
+        standalone.delete()
f5000e
+    standalone.create()
f5000e
+    standalone.open()
f5000e
+
f5000e
+    # Delete each instance in the end
f5000e
+    def fin():
f5000e
+        standalone.delete()
f5000e
+    request.addfinalizer(fin)
f5000e
+
f5000e
+    # Clear out the tmp dir
f5000e
+    standalone.clearTmpDir(__file__)
f5000e
+
f5000e
+    return TopologyStandalone(standalone)
f5000e
+
f5000e
+
f5000e
+@pytest.fixture(scope="module")
f5000e
+def test_user(topology):
f5000e
+    """User for binding operation"""
f5000e
+
f5000e
+    try:
f5000e
+        topology.standalone.add_s(Entry((TEST_USER_DN, {
f5000e
+                                        'objectclass': 'top person'.split(),
f5000e
+                                        'objectclass': 'organizationalPerson',
f5000e
+                                        'objectclass': 'inetorgperson',
f5000e
+                                        'cn': TEST_USER_NAME,
f5000e
+                                        'sn': TEST_USER_NAME,
f5000e
+                                        'userpassword': TEST_USER_PWD,
f5000e
+                                        'mail': '%s@redhat.com' % TEST_USER_NAME,
f5000e
+                                        'uid': TEST_USER_NAME
f5000e
+                                        })))
f5000e
+    except ldap.LDAPError as e:
f5000e
+        log.error('Failed to add user (%s): error (%s)' % (TEST_USER_DN,
f5000e
+                                                           e.message['desc']))
f5000e
+        raise e
f5000e
+
f5000e
+
f5000e
+def add_users(topology, users_num):
f5000e
+    """Add users to the default suffix
f5000e
+    and return a list of added user DNs.
f5000e
+    """
f5000e
+
f5000e
+    users_list = []
f5000e
+    log.info('Adding %d users' % users_num)
f5000e
+    for num in sample(range(1000), users_num):
f5000e
+        num_ran = int(round(num))
f5000e
+        USER_NAME = 'test%05d' % num_ran
f5000e
+        USER_DN = 'uid=%s,%s' % (USER_NAME, DEFAULT_SUFFIX)
f5000e
+        users_list.append(USER_DN)
f5000e
+        try:
f5000e
+            topology.standalone.add_s(Entry((USER_DN, {
f5000e
+                                             'objectclass': 'top person'.split(),
f5000e
+                                             'objectclass': 'organizationalPerson',
f5000e
+                                             'objectclass': 'inetorgperson',
f5000e
+                                             'cn': USER_NAME,
f5000e
+                                             'sn': USER_NAME,
f5000e
+                                             'userpassword': 'pass%s' % num_ran,
f5000e
+                                             'mail': '%s@redhat.com' % USER_NAME,
f5000e
+                                             'uid': USER_NAME
f5000e
+                                              })))
f5000e
+        except ldap.LDAPError as e:
f5000e
+            log.error('Failed to add user (%s): error (%s)' % (USER_DN,
f5000e
+                                                               e.message['desc']))
f5000e
+            raise e
f5000e
+    return users_list
f5000e
+
f5000e
+
f5000e
+def del_users(topology, users_list):
f5000e
+    """Delete users with DNs from given list"""
f5000e
+
f5000e
+    log.info('Deleting %d users' % len(users_list))
f5000e
+    for user_dn in users_list:
f5000e
+        try:
f5000e
+            topology.standalone.delete_s(user_dn)
f5000e
+        except ldap.LDAPError as e:
f5000e
+            log.error('Failed to delete user (%s): error (%s)' % (user_dn,
f5000e
+                                                                  e.message['desc']))
f5000e
+            raise e
f5000e
+
f5000e
+
f5000e
+def change_conf_attr(topology, suffix, attr_name, attr_value):
f5000e
+    """Change configurational attribute in the given suffix.
f5000e
+    Funtion returns previous attribute value.
f5000e
+    """
f5000e
+
f5000e
+    try:
f5000e
+        entries = topology.standalone.search_s(suffix, ldap.SCOPE_BASE,
f5000e
+                                                'objectclass=top',
f5000e
+                                                [attr_name])
f5000e
+        attr_value_bck = entries[0].data.get(attr_name)
f5000e
+        log.info('Set %s to %s. Previous value - %s. Modified suffix - %s.' % (
f5000e
+                        attr_name, attr_value, attr_value_bck, suffix))
f5000e
+        if attr_value is None:
f5000e
+            topology.standalone.modify_s(suffix, [(ldap.MOD_DELETE,
f5000e
+                                                        attr_name,
f5000e
+                                                        attr_value)])
f5000e
+        else:
f5000e
+            topology.standalone.modify_s(suffix, [(ldap.MOD_REPLACE,
f5000e
+                                                        attr_name,
f5000e
+                                                        attr_value)])
f5000e
+    except ldap.LDAPError as e:
f5000e
+           log.error('Failed to change attr value (%s): error (%s)' % (attr_name,
f5000e
+                                                                       e.message['desc']))
f5000e
+           raise e
f5000e
+
f5000e
+    return attr_value_bck
f5000e
+
f5000e
+
f5000e
+def paged_search(topology, controls, search_flt, searchreq_attrlist):
f5000e
+    """Search at the DEFAULT_SUFFIX with ldap.SCOPE_SUBTREE
f5000e
+    using Simple Paged Control(should the first item in the
f5000e
+    list controls.
f5000e
+    Return the list with results summarized from all pages
f5000e
+    """
f5000e
+
f5000e
+    pages = 0
f5000e
+    pctrls = []
f5000e
+    all_results = []
f5000e
+    req_ctrl = controls[0]
f5000e
+    msgid = topology.standalone.search_ext(DEFAULT_SUFFIX,
f5000e
+                                           ldap.SCOPE_SUBTREE,
f5000e
+                                           search_flt,
f5000e
+                                           searchreq_attrlist,
f5000e
+                                           serverctrls=controls)
f5000e
+    while True:
f5000e
+        log.info('Getting page %d' % (pages,))
f5000e
+        rtype, rdata, rmsgid, rctrls = topology.standalone.result3(msgid)
f5000e
+        all_results.extend(rdata)
f5000e
+        pages += 1
f5000e
+        pctrls = [
f5000e
+            c
f5000e
+            for c in rctrls
f5000e
+            if c.controlType == SimplePagedResultsControl.controlType
f5000e
+        ]
f5000e
+
f5000e
+        if pctrls:
f5000e
+            if pctrls[0].cookie:
f5000e
+                # Copy cookie from response control to request control
f5000e
+                req_ctrl.cookie = pctrls[0].cookie
f5000e
+                msgid = topology.standalone.search_ext(DEFAULT_SUFFIX,
f5000e
+                                                       ldap.SCOPE_SUBTREE,
f5000e
+                                                       search_flt,
f5000e
+                                                       searchreq_attrlist,
f5000e
+                                                       serverctrls=controls)
f5000e
+            else:
f5000e
+                break # no more pages available
f5000e
+        else:
f5000e
+            break
f5000e
+
f5000e
+    assert not pctrls[0].cookie
f5000e
+    return all_results
f5000e
+
f5000e
+
f5000e
+def test_ticket48808(topology, test_user):
f5000e
+    log.info('Run multiple paging controls on a single connection')
f5000e
+    users_num = 100
f5000e
+    page_size = 30
f5000e
+    users_list = add_users(topology, users_num)
f5000e
+    search_flt = r'(uid=test*)'
f5000e
+    searchreq_attrlist = ['dn', 'sn']
f5000e
+
f5000e
+    log.info('Set user bind')
f5000e
+    topology.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD)
f5000e
+
f5000e
+    log.info('Create simple paged results control instance')
f5000e
+    req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
f5000e
+    controls = [req_ctrl]
f5000e
+
f5000e
+    for ii in xrange(3):
f5000e
+        log.info('Iteration %d' % ii)
f5000e
+        msgid = topology.standalone.search_ext(DEFAULT_SUFFIX,
f5000e
+                                                ldap.SCOPE_SUBTREE,
f5000e
+                                                search_flt,
f5000e
+                                                searchreq_attrlist,
f5000e
+                                                serverctrls=controls)
f5000e
+        rtype, rdata, rmsgid, rctrls = topology.standalone.result3(msgid)
f5000e
+        pctrls = [
f5000e
+            c
f5000e
+            for c in rctrls
f5000e
+            if c.controlType == SimplePagedResultsControl.controlType
f5000e
+        ]
f5000e
+
f5000e
+        req_ctrl.cookie = pctrls[0].cookie
f5000e
+        msgid = topology.standalone.search_ext(DEFAULT_SUFFIX,
f5000e
+                                                ldap.SCOPE_SUBTREE,
f5000e
+                                                search_flt,
f5000e
+                                                searchreq_attrlist,
f5000e
+                                                serverctrls=controls)
f5000e
+    log.info('Set Directory Manager bind back')
f5000e
+    topology.standalone.simple_bind_s(DN_DM, PASSWORD)
f5000e
+    del_users(topology, users_list)
f5000e
+
f5000e
+    log.info('Abandon the search')
f5000e
+    users_num = 10
f5000e
+    page_size = 0
f5000e
+    users_list = add_users(topology, users_num)
f5000e
+    search_flt = r'(uid=test*)'
f5000e
+    searchreq_attrlist = ['dn', 'sn']
f5000e
+
f5000e
+    log.info('Set user bind')
f5000e
+    topology.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD)
f5000e
+
f5000e
+    log.info('Create simple paged results control instance')
f5000e
+    req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
f5000e
+    controls = [req_ctrl]
f5000e
+
f5000e
+    msgid = topology.standalone.search_ext(DEFAULT_SUFFIX,
f5000e
+                                           ldap.SCOPE_SUBTREE,
f5000e
+                                           search_flt,
f5000e
+                                           searchreq_attrlist,
f5000e
+                                           serverctrls=controls)
f5000e
+    rtype, rdata, rmsgid, rctrls = topology.standalone.result3(msgid)
f5000e
+    pctrls = [
f5000e
+        c
f5000e
+        for c in rctrls
f5000e
+        if c.controlType == SimplePagedResultsControl.controlType
f5000e
+    ]
f5000e
+    assert not pctrls[0].cookie
f5000e
+
f5000e
+    log.info('Set Directory Manager bind back')
f5000e
+    topology.standalone.simple_bind_s(DN_DM, PASSWORD)
f5000e
+    del_users(topology, users_list)
f5000e
+
f5000e
+    log.info("Search should fail with 'nsPagedSizeLimit = 5'"
f5000e
+             "and 'nsslapd-pagedsizelimit = 15' with 10 users")
f5000e
+    conf_attr = '15'
f5000e
+    user_attr = '5'
f5000e
+    expected_rs = ldap.SIZELIMIT_EXCEEDED
f5000e
+    users_num = 10
f5000e
+    page_size = 10
f5000e
+    users_list = add_users(topology, users_num)
f5000e
+    search_flt = r'(uid=test*)'
f5000e
+    searchreq_attrlist = ['dn', 'sn']
f5000e
+    conf_attr_bck = change_conf_attr(topology, DN_CONFIG,
f5000e
+                                        'nsslapd-pagedsizelimit', conf_attr)
f5000e
+    user_attr_bck = change_conf_attr(topology, TEST_USER_DN,
f5000e
+                                        'nsPagedSizeLimit', user_attr)
f5000e
+
f5000e
+    log.info('Set user bind')
f5000e
+    topology.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD)
f5000e
+
f5000e
+    log.info('Create simple paged results control instance')
f5000e
+    req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
f5000e
+    controls = [req_ctrl]
f5000e
+
f5000e
+    log.info('Expect to fail with SIZELIMIT_EXCEEDED')
f5000e
+    with pytest.raises(expected_rs):
f5000e
+        all_results = paged_search(topology, controls,
f5000e
+                                   search_flt, searchreq_attrlist)
f5000e
+
f5000e
+    log.info('Set Directory Manager bind back')
f5000e
+    topology.standalone.simple_bind_s(DN_DM, PASSWORD)
f5000e
+    del_users(topology, users_list)
f5000e
+    change_conf_attr(topology, DN_CONFIG,
f5000e
+                     'nsslapd-pagedsizelimit', conf_attr_bck)
f5000e
+    change_conf_attr(topology, TEST_USER_DN,
f5000e
+                     'nsPagedSizeLimit', user_attr_bck)
f5000e
+
f5000e
+    log.info("Search should pass with 'nsPagedSizeLimit = 15'"
f5000e
+             "and 'nsslapd-pagedsizelimit = 5' with 10 users")
f5000e
+    conf_attr = '5'
f5000e
+    user_attr = '15'
f5000e
+    users_num = 10
f5000e
+    page_size = 10
f5000e
+    users_list = add_users(topology, users_num)
f5000e
+    search_flt = r'(uid=test*)'
f5000e
+    searchreq_attrlist = ['dn', 'sn']
f5000e
+    conf_attr_bck = change_conf_attr(topology, DN_CONFIG,
f5000e
+                                    'nsslapd-pagedsizelimit', conf_attr)
f5000e
+    user_attr_bck = change_conf_attr(topology, TEST_USER_DN,
f5000e
+                                    'nsPagedSizeLimit', user_attr)
f5000e
+
f5000e
+    log.info('Set user bind')
f5000e
+    topology.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD)
f5000e
+
f5000e
+    log.info('Create simple paged results control instance')
f5000e
+    req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
f5000e
+    controls = [req_ctrl]
f5000e
+
f5000e
+    log.info('Search should PASS')
f5000e
+    all_results = paged_search(topology, controls,
f5000e
+                               search_flt, searchreq_attrlist)
f5000e
+    log.info('%d results' % len(all_results))
f5000e
+    assert len(all_results) == len(users_list)
f5000e
+
f5000e
+    log.info('Set Directory Manager bind back')
f5000e
+    topology.standalone.simple_bind_s(DN_DM, PASSWORD)
f5000e
+    del_users(topology, users_list)
f5000e
+    change_conf_attr(topology, DN_CONFIG,
f5000e
+                    'nsslapd-pagedsizelimit', conf_attr_bck)
f5000e
+    change_conf_attr(topology, TEST_USER_DN,
f5000e
+                    'nsPagedSizeLimit', user_attr_bck)
f5000e
+
f5000e
+
f5000e
+if __name__ == '__main__':
f5000e
+    # Run isolated
f5000e
+    # -s for DEBUG mode
f5000e
+    CURRENT_FILE = os.path.realpath(__file__)
f5000e
+    pytest.main("-s %s" % CURRENT_FILE)
f5000e
-- 
f5000e
2.4.11
f5000e