From 8893285f81ed230e42f67190a5f70b82a6f15947 Mon Sep 17 00:00:00 2001
From: Simon Pichugin <spichugi@redhat.com>
Date: Thu, 14 Jul 2016 14:14:12 +0200
Subject: [PATCH] Ticket 48752 - Add CI test

Description: Test that search with simple paged result control works
properly on two suffixes (one is parent of the other) and the logs
show right pr_cookie values.

https://fedorahosted.org/389/ticket/48752

Reviewed by: ?
---
 .../suites/paged_results/paged_results_test.py     | 180 +++++++++++++++++----
 1 file changed, 146 insertions(+), 34 deletions(-)

diff --git a/dirsrvtests/tests/suites/paged_results/paged_results_test.py b/dirsrvtests/tests/suites/paged_results/paged_results_test.py
index 9c1978e..2a1116b 100644
--- a/dirsrvtests/tests/suites/paged_results/paged_results_test.py
+++ b/dirsrvtests/tests/suites/paged_results/paged_results_test.py
@@ -12,8 +12,7 @@ import logging
 import pytest
 from random import sample
 from ldap.controls import SimplePagedResultsControl, GetEffectiveRightsControl
-from lib389 import DirSrv, Entry, tools, tasks
-from lib389.tools import DirSrvTools
+from lib389 import DirSrv, Entry
 from lib389._constants import *
 from lib389.properties import *
 from lib389.tasks import *
@@ -24,8 +23,14 @@ logging.getLogger(__name__).setLevel(logging.DEBUG)
 log = logging.getLogger(__name__)
 
 TEST_USER_NAME = 'simplepaged_test'
-TEST_USER_DN = 'uid=%s,%s' % (TEST_USER_NAME, DEFAULT_SUFFIX)
+TEST_USER_DN = 'uid={},{}'.format(TEST_USER_NAME, DEFAULT_SUFFIX)
 TEST_USER_PWD = 'simplepaged_test'
+NEW_SUFFIX_1_NAME = 'test_parent'
+NEW_SUFFIX_1 = 'o={}'.format(NEW_SUFFIX_1_NAME)
+NEW_SUFFIX_2_NAME = 'child'
+NEW_SUFFIX_2 = 'ou={},{}'.format(NEW_SUFFIX_2_NAME, NEW_SUFFIX_1)
+NEW_BACKEND_1 = 'parent_base'
+NEW_BACKEND_2 = 'child_base'
 
 
 class TopologyStandalone(object):
@@ -62,9 +67,10 @@ def topology(request):
 
 
 @pytest.fixture(scope="module")
-def test_user(topology):
+def test_user(topology, request):
     """User for binding operation"""
 
+    log.info('Adding user {}'.format(TEST_USER_DN))
     try:
         topology.standalone.add_s(Entry((TEST_USER_DN, {
                                         'objectclass': 'top person'.split(),
@@ -81,8 +87,63 @@ def test_user(topology):
                                                            e.message['desc']))
         raise e
 
+    def fin():
+        log.info('Deleting user {}'.format(TEST_USER_DN))
+        topology.standalone.delete_s(TEST_USER_DN)
+    request.addfinalizer(fin)
+
+
+@pytest.fixture(scope="module")
+def new_suffixes(topology):
+    """Add two suffixes with backends, one is a parent
+    of the another
+    """
+
+    log.info('Adding suffix:{} and backend: {}'.format(NEW_SUFFIX_1, NEW_BACKEND_1))
+    topology.standalone.backend.create(NEW_SUFFIX_1,
+                                       {BACKEND_NAME: NEW_BACKEND_1})
+    topology.standalone.mappingtree.create(NEW_SUFFIX_1,
+                                           bename=NEW_BACKEND_1)
+    try:
+        topology.standalone.add_s(Entry((NEW_SUFFIX_1, {
+                                        'objectclass': 'top',
+                                        'objectclass': 'organization',
+                                        'o': NEW_SUFFIX_1_NAME
+                                        })))
+    except ldap.LDAPError as e:
+        log.error('Failed to add suffix ({}): error ({})'.format(NEW_SUFFIX_1,
+                                                                 e.message['desc']))
+        raise
 
-def add_users(topology, users_num):
+    log.info('Adding suffix:{} and backend: {}'.format(NEW_SUFFIX_2, NEW_BACKEND_2))
+    topology.standalone.backend.create(NEW_SUFFIX_2,
+                                       {BACKEND_NAME: NEW_BACKEND_2})
+    topology.standalone.mappingtree.create(NEW_SUFFIX_2,
+                                           bename=NEW_BACKEND_2,
+                                           parent=NEW_SUFFIX_1)
+
+    try:
+        topology.standalone.add_s(Entry((NEW_SUFFIX_2, {
+                                        'objectclass': 'top',
+                                        'objectclass': 'organizationalunit',
+                                        'ou': NEW_SUFFIX_2_NAME
+                                        })))
+    except ldap.LDAPError as e:
+        log.error('Failed to add suffix ({}): error ({})'.format(NEW_SUFFIX_2,
+                                                                 e.message['desc']))
+        raise
+
+    log.info('Adding ACI to allow our test user to search')
+    ACI_TARGET = '(targetattr != "userPassword || aci")'
+    ACI_ALLOW = '(version 3.0; acl "Enable anonymous access";allow (read, search, compare)'
+    ACI_SUBJECT = '(userdn = "ldap:///anyone");)'
+    ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
+
+    mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
+    topology.standalone.modify_s(NEW_SUFFIX_1, mod)
+
+
+def add_users(topology, users_num, suffix):
     """Add users to the default suffix
 
     Return the list of added user DNs.
@@ -93,7 +154,7 @@ def add_users(topology, users_num):
     for num in sample(range(1000), users_num):
         num_ran = int(round(num))
         USER_NAME = 'test%05d' % num_ran
-        USER_DN = 'uid=%s,%s' % (USER_NAME, DEFAULT_SUFFIX)
+        USER_DN = 'uid=%s,%s' % (USER_NAME, suffix)
         users_list.append(USER_DN)
         try:
             topology.standalone.add_s(Entry((USER_DN, {
@@ -154,7 +215,7 @@ def change_conf_attr(topology, suffix, attr_name, attr_value):
     return attr_value_bck
 
 
-def paged_search(topology, controls, search_flt, searchreq_attrlist):
+def paged_search(topology, suffix, controls, search_flt, searchreq_attrlist):
     """Search at the DEFAULT_SUFFIX with ldap.SCOPE_SUBTREE
     using Simple Paged Control(should the first item in the
     list controls.
@@ -167,7 +228,7 @@ def paged_search(topology, controls, search_flt, searchreq_attrlist):
     pctrls = []
     all_results = []
     req_ctrl = controls[0]
-    msgid = topology.standalone.search_ext(DEFAULT_SUFFIX,
+    msgid = topology.standalone.search_ext(suffix,
                                            ldap.SCOPE_SUBTREE,
                                            search_flt,
                                            searchreq_attrlist,
@@ -187,7 +248,7 @@ def paged_search(topology, controls, search_flt, searchreq_attrlist):
             if pctrls[0].cookie:
                 # Copy cookie from response control to request control
                 req_ctrl.cookie = pctrls[0].cookie
-                msgid = topology.standalone.search_ext(DEFAULT_SUFFIX,
+                msgid = topology.standalone.search_ext(suffix,
                                                        ldap.SCOPE_SUBTREE,
                                                        search_flt,
                                                        searchreq_attrlist,
@@ -218,7 +279,7 @@ def test_search_success(topology, test_user, page_size, users_num):
     :Assert: All users should be found
     """
 
-    users_list = add_users(topology, users_num)
+    users_list = add_users(topology, users_num, DEFAULT_SUFFIX)
     search_flt = r'(uid=test*)'
     searchreq_attrlist = ['dn', 'sn']
 
@@ -229,7 +290,7 @@ def test_search_success(topology, test_user, page_size, users_num):
         log.info('Create simple paged results control instance')
         req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
 
-        all_results = paged_search(topology, [req_ctrl],
+        all_results = paged_search(topology, DEFAULT_SUFFIX, [req_ctrl],
                                    search_flt, searchreq_attrlist)
 
         log.info('%d results' % len(all_results))
@@ -270,7 +331,7 @@ def test_search_limits_fail(topology, test_user, page_size, users_num,
     :Assert: Should fail with appropriate exception
     """
 
-    users_list = add_users(topology, users_num)
+    users_list = add_users(topology, users_num, DEFAULT_SUFFIX)
     attr_value_bck = change_conf_attr(topology, suffix, attr_name, attr_value)
     conf_param_dict = {attr_name: attr_value}
     search_flt = r'(uid=test*)'
@@ -359,7 +420,7 @@ def test_search_sort_success(topology, test_user):
 
     users_num = 50
     page_size = 5
-    users_list = add_users(topology, users_num)
+    users_list = add_users(topology, users_num, DEFAULT_SUFFIX)
     search_flt = r'(uid=test*)'
     searchreq_attrlist = ['dn', 'sn']
 
@@ -374,7 +435,7 @@ def test_search_sort_success(topology, test_user):
         log.info('Initiate ldapsearch with created control instance')
         log.info('Collect data with sorting')
         controls = [req_ctrl, sort_ctrl]
-        results_sorted = paged_search(topology, controls,
+        results_sorted = paged_search(topology, DEFAULT_SUFFIX, controls,
                                       search_flt, searchreq_attrlist)
 
         log.info('Substring numbers from user DNs')
@@ -407,7 +468,7 @@ def test_search_abandon(topology, test_user):
 
     users_num = 10
     page_size = 2
-    users_list = add_users(topology, users_num)
+    users_list = add_users(topology, users_num, DEFAULT_SUFFIX)
     search_flt = r'(uid=test*)'
     searchreq_attrlist = ['dn', 'sn']
 
@@ -459,7 +520,7 @@ def test_search_with_timelimit(topology, test_user):
     users_num = 100
     page_size = 50
     timelimit = 5
-    users_list = add_users(topology, users_num)
+    users_list = add_users(topology, users_num, DEFAULT_SUFFIX)
     search_flt = r'(uid=test*)'
     searchreq_attrlist = ['dn', 'sn']
 
@@ -541,7 +602,7 @@ def test_search_dns_ip_aci(topology, test_user, aci_subject):
 
     users_num = 100
     page_size = 5
-    users_list = add_users(topology, users_num)
+    users_list = add_users(topology, users_num, DEFAULT_SUFFIX)
     search_flt = r'(uid=test*)'
     searchreq_attrlist = ['dn', 'sn']
 
@@ -572,7 +633,7 @@ def test_search_dns_ip_aci(topology, test_user, aci_subject):
         log.info('Initiate three searches with a paged results control')
         for ii in range(3):
             log.info('%d search' % (ii + 1))
-            all_results = paged_search(topology, controls,
+            all_results = paged_search(topology, DEFAULT_SUFFIX, controls,
                                        search_flt, searchreq_attrlist)
             log.info('%d results' % len(all_results))
             assert len(all_results) == len(users_list)
@@ -611,7 +672,7 @@ def test_search_multiple_paging(topology, test_user):
 
     users_num = 100
     page_size = 30
-    users_list = add_users(topology, users_num)
+    users_list = add_users(topology, users_num, DEFAULT_SUFFIX)
     search_flt = r'(uid=test*)'
     searchreq_attrlist = ['dn', 'sn']
 
@@ -671,7 +732,7 @@ def test_search_invalid_cookie(topology, test_user, invalid_cookie):
 
     users_num = 100
     page_size = 50
-    users_list = add_users(topology, users_num)
+    users_list = add_users(topology, users_num, DEFAULT_SUFFIX)
     search_flt = r'(uid=test*)'
     searchreq_attrlist = ['dn', 'sn']
 
@@ -723,7 +784,7 @@ def test_search_abandon_with_zero_size(topology, test_user):
 
     users_num = 10
     page_size = 0
-    users_list = add_users(topology, users_num)
+    users_list = add_users(topology, users_num, DEFAULT_SUFFIX)
     search_flt = r'(uid=test*)'
     searchreq_attrlist = ['dn', 'sn']
 
@@ -777,7 +838,7 @@ def test_search_pagedsizelimit_success(topology, test_user):
     attr_value = '20'
     attr_value_bck = change_conf_attr(topology, DN_CONFIG,
                                       attr_name, attr_value)
-    users_list = add_users(topology, users_num)
+    users_list = add_users(topology, users_num, DEFAULT_SUFFIX)
     search_flt = r'(uid=test*)'
     searchreq_attrlist = ['dn', 'sn']
 
@@ -789,7 +850,7 @@ def test_search_pagedsizelimit_success(topology, test_user):
         req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
         controls = [req_ctrl]
 
-        all_results = paged_search(topology, controls,
+        all_results = paged_search(topology, DEFAULT_SUFFIX, controls,
                                    search_flt, searchreq_attrlist)
 
         log.info('%d results' % len(all_results))
@@ -836,7 +897,7 @@ def test_search_nspagedsizelimit(topology, test_user,
 
     users_num = 10
     page_size = 10
-    users_list = add_users(topology, users_num)
+    users_list = add_users(topology, users_num, DEFAULT_SUFFIX)
     search_flt = r'(uid=test*)'
     searchreq_attrlist = ['dn', 'sn']
     conf_attr_bck = change_conf_attr(topology, DN_CONFIG,
@@ -855,11 +916,11 @@ def test_search_nspagedsizelimit(topology, test_user,
         if expected_rs == ldap.SIZELIMIT_EXCEEDED:
             log.info('Expect to fail with SIZELIMIT_EXCEEDED')
             with pytest.raises(expected_rs):
-                all_results = paged_search(topology, controls,
+                all_results = paged_search(topology, DEFAULT_SUFFIX, controls,
                                            search_flt, searchreq_attrlist)
         elif expected_rs == 'PASS':
             log.info('Expect to pass')
-            all_results = paged_search(topology, controls,
+            all_results = paged_search(topology, DEFAULT_SUFFIX, controls,
                                        search_flt, searchreq_attrlist)
             log.info('%d results' % len(all_results))
             assert len(all_results) == len(users_list)
@@ -907,7 +968,7 @@ def test_search_paged_limits(topology, test_user, conf_attr_values, expected_rs)
 
     users_num = 101
     page_size = 10
-    users_list = add_users(topology, users_num)
+    users_list = add_users(topology, users_num, DEFAULT_SUFFIX)
     search_flt = r'(uid=test*)'
     searchreq_attrlist = ['dn', 'sn']
     size_attr_bck = change_conf_attr(topology, DN_CONFIG,
@@ -930,11 +991,11 @@ def test_search_paged_limits(topology, test_user, conf_attr_values, expected_rs)
         if expected_rs == ldap.ADMINLIMIT_EXCEEDED:
             log.info('Expect to fail with ADMINLIMIT_EXCEEDED')
             with pytest.raises(expected_rs):
-                all_results = paged_search(topology, controls,
+                all_results = paged_search(topology, DEFAULT_SUFFIX, controls,
                                            search_flt, searchreq_attrlist)
         elif expected_rs == 'PASS':
             log.info('Expect to pass')
-            all_results = paged_search(topology, controls,
+            all_results = paged_search(topology, DEFAULT_SUFFIX, controls,
                                        search_flt, searchreq_attrlist)
             log.info('%d results' % len(all_results))
             assert len(all_results) == len(users_list)
@@ -986,7 +1047,7 @@ def test_search_paged_user_limits(topology, test_user, conf_attr_values, expecte
 
     users_num = 101
     page_size = 10
-    users_list = add_users(topology, users_num)
+    users_list = add_users(topology, users_num, DEFAULT_SUFFIX)
     search_flt = r'(uid=test*)'
     searchreq_attrlist = ['dn', 'sn']
     lookthrough_attr_bck = change_conf_attr(topology, 'cn=config,%s' % DN_LDBM,
@@ -1009,11 +1070,11 @@ def test_search_paged_user_limits(topology, test_user, conf_attr_values, expecte
         if expected_rs == ldap.ADMINLIMIT_EXCEEDED:
             log.info('Expect to fail with ADMINLIMIT_EXCEEDED')
             with pytest.raises(expected_rs):
-                all_results = paged_search(topology, controls,
+                all_results = paged_search(topology, DEFAULT_SUFFIX, controls,
                                            search_flt, searchreq_attrlist)
         elif expected_rs == 'PASS':
             log.info('Expect to pass')
-            all_results = paged_search(topology, controls,
+            all_results = paged_search(topology, DEFAULT_SUFFIX, controls,
                                        search_flt, searchreq_attrlist)
             log.info('%d results' % len(all_results))
             assert len(all_results) == len(users_list)
@@ -1048,7 +1109,7 @@ def test_ger_basic(topology, test_user):
              an 'attributeLevelRights' returned
     """
 
-    users_list = add_users(topology, 20)
+    users_list = add_users(topology, 20, DEFAULT_SUFFIX)
     search_flt = r'(uid=test*)'
     searchreq_attrlist = ['dn', 'sn']
     page_size = 4
@@ -1061,7 +1122,7 @@ def test_ger_basic(topology, test_user):
         spr_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
         ger_ctrl = GetEffectiveRightsControl(True, "dn: " + DN_DM)
 
-        all_results = paged_search(topology, [spr_ctrl, ger_ctrl],
+        all_results = paged_search(topology, DEFAULT_SUFFIX, [spr_ctrl, ger_ctrl],
                                    search_flt, searchreq_attrlist)
 
         log.info('{} results'.format(len(all_results)))
@@ -1073,6 +1134,57 @@ def test_ger_basic(topology, test_user):
         del_users(topology, users_list)
 
 
+def test_multi_suffix_search(topology, test_user, new_suffixes):
+    """Verify that page result search returns empty cookie
+    if there is no returned entry.
+
+    :Feature: Simple paged results
+
+    :Setup: Standalone instance, test user for binding,
+            two suffixes with backends, one is inserted into another,
+            10 users for the search base within each suffix
+
+    :Steps: 1. Bind as test user
+            2. Search through all 20 added users with a simple paged control
+               using page_size = 4
+            3. Wait some time logs to be updated
+            3. Check access log
+
+    :Assert: All users should be found, the access log should contain
+             the pr_cookie for each page request and it should be equal 0,
+             except the last one should be equal -1
+    """
+
+    search_flt = r'(uid=test*)'
+    searchreq_attrlist = ['dn', 'sn']
+    page_size = 4
+    users_num = 20
+
+    add_users(topology, users_num / 2, NEW_SUFFIX_1)
+    add_users(topology, users_num / 2, NEW_SUFFIX_2)
+
+    log.info('Set DM bind')
+    topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+
+    log.info('Create simple paged results control instance')
+    req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
+
+    all_results = paged_search(topology, NEW_SUFFIX_1, [req_ctrl],
+                               search_flt, searchreq_attrlist)
+
+    log.info('{} results'.format(len(all_results)))
+    assert len(all_results) == users_num
+
+    log.info('Waiting for logs to be updated')
+    time.sleep(30)
+    access_log_lines = topology.standalone.ds_access_log.match('.*pr_cookie=.*')
+    pr_cookie_list = ([line.rsplit('=', 1)[-1] for line in access_log_lines])
+    pr_cookie_list = [int(pr_cookie) for pr_cookie in pr_cookie_list]
+    log.info('Assert that last pr_cookie == -1 and others pr_cookie == 0')
+    assert all(pr_cookie == 0 for pr_cookie in pr_cookie_list[0:-1])
+    assert pr_cookie_list[-1] == -1
+
+
 if __name__ == '__main__':
     # Run isolated
     # -s for DEBUG mode
-- 
2.5.5

