From eeea8dc0cebb69cc50b5f833413ad55df85c9f10 Mon Sep 17 00:00:00 2001
From: Noriko Hosoi <nhosoi@redhat.com>
Date: Fri, 18 Dec 2015 17:13:33 -0800
Subject: [PATCH 2/2] Ticket #48294 - CI test: added test cases for ticket
 48294

Description: Linked Attributes plug-in - won't update links after MODRDN operation
---
 dirsrvtests/tickets/ticket48294_test.py | 290 ++++++++++++++++++++++++++++++++
 1 file changed, 290 insertions(+)
 create mode 100644 dirsrvtests/tickets/ticket48294_test.py

diff --git a/dirsrvtests/tickets/ticket48294_test.py b/dirsrvtests/tickets/ticket48294_test.py
new file mode 100644
index 0000000..109a67e
--- /dev/null
+++ b/dirsrvtests/tickets/ticket48294_test.py
@@ -0,0 +1,290 @@
+# --- BEGIN COPYRIGHT BLOCK ---
+# Copyright (C) 2015 Red Hat, Inc.
+# All rights reserved.
+#
+# License: GPL (version 3 or any later version).
+# See LICENSE for details. 
+# --- END COPYRIGHT BLOCK ---
+#
+import os
+import sys
+import time
+import ldap
+import logging
+import pytest
+import shutil
+from lib389 import DirSrv, Entry, tools
+from lib389 import DirSrvTools
+from lib389.tools import DirSrvTools
+from lib389._constants import *
+from lib389.properties import *
+
+log = logging.getLogger(__name__)
+
+installation_prefix = None
+
+LINKEDATTR_PLUGIN = 'cn=Linked Attributes,cn=plugins,cn=config'
+MANAGER_LINK = 'cn=Manager Link,' + LINKEDATTR_PLUGIN
+OU_PEOPLE = 'ou=People,' + DEFAULT_SUFFIX
+LINKTYPE = 'directReport'
+MANAGEDTYPE = 'manager'
+
+class TopologyStandalone(object):
+    def __init__(self, standalone):
+        standalone.open()
+        self.standalone = standalone
+
+
+@pytest.fixture(scope="module")
+def topology(request):
+    '''
+    This fixture is used to standalone topology for the 'module'.
+    '''
+    global installation_prefix
+
+    if installation_prefix:
+        args_instance[SER_DEPLOYED_DIR] = installation_prefix
+
+    standalone = DirSrv(verbose=False)
+
+    # Args for the standalone instance
+    args_instance[SER_HOST] = HOST_STANDALONE
+    args_instance[SER_PORT] = PORT_STANDALONE
+    args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
+    args_standalone = args_instance.copy()
+    standalone.allocate(args_standalone)
+
+    # Get the status of the instance and restart it if it exists
+    instance_standalone = standalone.exists()
+
+    # Remove the instance
+    if instance_standalone:
+        standalone.delete()
+
+    # Create the instance
+    standalone.create()
+
+    # Used to retrieve configuration information (dbdir, confdir...)
+    standalone.open()
+
+    # clear the tmp directory
+    standalone.clearTmpDir(__file__)
+
+    # Here we have standalone instance up and running
+    return TopologyStandalone(standalone)
+
+
+def _header(topology, label):
+    topology.standalone.log.info("###############################################")
+    topology.standalone.log.info("####### %s" % label)
+    topology.standalone.log.info("###############################################")
+
+def check_attr_val(topology, dn, attr, expected):
+    try:
+        centry = topology.standalone.search_s(dn, ldap.SCOPE_BASE, 'uid=*')
+        if centry:
+            val = centry[0].getValue(attr)
+            if val.lower() == expected.lower():
+                log.info('Value of %s is %s' % (attr, expected))
+            else:
+                log.info('Value of %s is not %s, but %s' % (attr, expected, val))
+                assert False
+        else:
+            log.fatal('Failed to get %s' % dn)
+            assert False
+    except ldap.LDAPError as e:
+        log.fatal('Failed to search ' + dn + ': ' + e.message['desc'])
+        assert False
+
+
+def _modrdn_entry(topology=None, entry_dn=None, new_rdn=None, del_old=0, new_superior=None):
+    assert topology is not None
+    assert entry_dn is not None
+    assert new_rdn is not None
+
+    topology.standalone.log.info("\n\n######################### MODRDN %s ######################\n" % new_rdn)
+    try:
+        if new_superior:
+            topology.standalone.rename_s(entry_dn, new_rdn, newsuperior=new_superior, delold=del_old)
+        else:
+            topology.standalone.rename_s(entry_dn, new_rdn, delold=del_old)
+    except ldap.NO_SUCH_ATTRIBUTE:
+        topology.standalone.log.info("accepted failure due to 47833: modrdn reports error.. but succeeds")
+        attempt = 0
+        if new_superior:
+            dn = "%s,%s" % (new_rdn, new_superior)
+            base = new_superior
+        else:
+            base = ','.join(entry_dn.split(",")[1:])
+            dn = "%s, %s" % (new_rdn, base)
+        myfilter = entry_dn.split(',')[0]
+
+        while attempt < 10:
+            try:
+                ent = topology.standalone.getEntry(dn, ldap.SCOPE_BASE, myfilter)
+                break
+            except ldap.NO_SUCH_OBJECT:
+                topology.standalone.log.info("Accept failure due to 47833: unable to find (base) a modrdn entry")
+                attempt += 1
+                time.sleep(1)
+        if attempt == 10:
+            ent = topology.standalone.getEntry(base, ldap.SCOPE_SUBTREE, myfilter)
+            ent = topology.standalone.getEntry(dn, ldap.SCOPE_BASE, myfilter)
+
+
+def _48294_init(topology):
+    """
+    Set up Linked Attribute
+    """
+    _header(topology, 'Testing Ticket 48294 - Linked Attributes plug-in - won\'t update links after MODRDN operation')
+
+    log.info('Enable Dynamic plugins, and the linked Attrs plugin')
+    try:
+        topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-dynamic-plugins', 'on')])
+    except ldap.LDAPError as e:
+        ldap.fatal('Failed to enable dynamic plugin!' + e.message['desc'])
+        assert False
+
+    try:
+        topology.standalone.plugins.enable(name=PLUGIN_LINKED_ATTRS)
+    except ValueError as e:
+        ldap.fatal('Failed to enable linked attributes plugin!' + e.message['desc'])
+        assert False
+
+    log.info('Add the plugin config entry')
+    try:
+        topology.standalone.add_s(Entry((MANAGER_LINK, {
+                          'objectclass': 'top extensibleObject'.split(),
+                          'cn': 'Manager Link',
+                          'linkType': LINKTYPE,
+                          'managedType': MANAGEDTYPE
+                          })))
+    except ldap.LDAPError as e:
+        log.fatal('Failed to add linked attr config entry: error ' + e.message['desc'])
+        assert False
+
+    log.info('Add 2 entries: manager1 and employee1')
+    try:
+        topology.standalone.add_s(Entry(('uid=manager1,%s' % OU_PEOPLE, {
+                          'objectclass': 'top extensibleObject'.split(),
+                          'uid': 'manager1'})))
+    except ldap.LDAPError as e:
+        log.fatal('Add manager1 failed: error ' + e.message['desc'])
+        assert False
+
+    try:
+        topology.standalone.add_s(Entry(('uid=employee1,%s' % OU_PEOPLE, {
+                          'objectclass': 'top extensibleObject'.split(),
+                          'uid': 'employee1'})))
+    except ldap.LDAPError as e:
+        log.fatal('Add employee1 failed: error ' + e.message['desc'])
+        assert False
+
+    log.info('Add linktype to manager1')
+    topology.standalone.modify_s('uid=manager1,%s' % OU_PEOPLE,
+                                 [(ldap.MOD_ADD, LINKTYPE, 'uid=employee1,%s' % OU_PEOPLE)])
+
+    log.info('Check managed attribute')
+    check_attr_val(topology, 'uid=employee1,%s' % OU_PEOPLE, MANAGEDTYPE, 'uid=manager1,%s' % OU_PEOPLE)
+
+    log.info('PASSED')
+
+
+def _48294_run_0(topology):
+    """
+    Rename employee1 to employee2 and adjust the value of directReport by replace
+    """
+    _header(topology, 'Case 0 - Rename employee1 and adjust the link type value by replace')
+
+    log.info('Rename employee1 to employee2')
+    _modrdn_entry(topology, entry_dn='uid=employee1,%s' % OU_PEOPLE, new_rdn='uid=employee2')
+
+    log.info('Modify the value of directReport to uid=employee2')
+    try:
+        topology.standalone.modify_s('uid=manager1,%s' % OU_PEOPLE,
+                                     [(ldap.MOD_REPLACE, LINKTYPE, 'uid=employee2,%s' % OU_PEOPLE)])
+    except ldap.LDAPError as e:
+        log.fatal('Failed to replace uid=employee1 with employee2: ' + e.message['desc'])
+        assert False
+
+    log.info('Check managed attribute')
+    check_attr_val(topology, 'uid=employee2,%s' % OU_PEOPLE, MANAGEDTYPE, 'uid=manager1,%s' % OU_PEOPLE)
+
+    log.info('PASSED')
+
+
+def _48294_run_1(topology):
+    """
+    Rename employee2 to employee3 and adjust the value of directReport by delete and add
+    """
+    _header(topology, 'Case 1 - Rename employee2 and adjust the link type value by delete and add')
+
+    log.info('Rename employee2 to employee3')
+    _modrdn_entry(topology, entry_dn='uid=employee2,%s' % OU_PEOPLE, new_rdn='uid=employee3')
+
+    log.info('Modify the value of directReport to uid=employee3')
+    try:
+        topology.standalone.modify_s('uid=manager1,%s' % OU_PEOPLE,
+                                     [(ldap.MOD_DELETE, LINKTYPE, 'uid=employee2,%s' % OU_PEOPLE)])
+    except ldap.LDAPError as e:
+        log.fatal('Failed to delete employee2: ' + e.message['desc'])
+        assert False
+
+    try:
+        topology.standalone.modify_s('uid=manager1,%s' % OU_PEOPLE,
+                                     [(ldap.MOD_ADD, LINKTYPE, 'uid=employee3,%s' % OU_PEOPLE)])
+    except ldap.LDAPError as e:
+        log.fatal('Failed to add employee3: ' + e.message['desc'])
+        assert False
+
+    log.info('Check managed attribute')
+    check_attr_val(topology, 'uid=employee3,%s' % OU_PEOPLE, MANAGEDTYPE, 'uid=manager1,%s' % OU_PEOPLE)
+
+    log.info('PASSED')
+
+
+def _48294_run_2(topology):
+    """
+    Rename manager1 to manager2 and make sure the managed attribute value is updated
+    """
+    _header(topology, 'Case 2 - Rename manager1 to manager2 and make sure the managed attribute value is updated')
+
+    log.info('Rename manager1 to manager2')
+    _modrdn_entry(topology, entry_dn='uid=manager1,%s' % OU_PEOPLE, new_rdn='uid=manager2')
+
+    log.info('Check managed attribute')
+    check_attr_val(topology, 'uid=employee3,%s' % OU_PEOPLE, MANAGEDTYPE, 'uid=manager2,%s' % OU_PEOPLE)
+
+    log.info('PASSED')
+
+
+def _48294_final(topology):
+    topology.standalone.delete()
+    log.info('All PASSED')
+
+
+def test_ticket48294(topology):
+    '''
+        run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
+        To run isolated without py.test, you need to
+            - edit this file and comment '@pytest.fixture' line before 'topology' function.
+            - set the installation prefix
+            - run this program
+    '''
+    global installation_prefix
+    installation_prefix = None
+
+    _48294_init(topology)
+
+    _48294_run_0(topology)
+    _48294_run_1(topology)
+    _48294_run_2(topology)
+
+    _48294_final(topology)
+
+if __name__ == '__main__':
+    # Run isolated
+    # -s for DEBUG mode
+
+    CURRENT_FILE = os.path.realpath(__file__)
+    pytest.main("-s %s" % CURRENT_FILE)
-- 
2.4.3

