|
|
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 |
|