dirsrvtests/tickets/ticket48295_test.py | 212 ++++++++++++++++++++++++
ldap/servers/plugins/linkedattrs/linked_attrs.c | 20 ++
2 files changed, 232 insertions(+)
New commits:
commit 63b8ecee2d6d24c5de5d7b826a5bb47bc83ee45d
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Mon Dec 21 17:27:06 2015 -0800
Ticket #48295 - CI test: added test cases for ticket 48295
Description: Entry cache is not rolled back -- Linked Attributes
plug-in - wrong behaviour when adding valid and broken links
diff --git a/dirsrvtests/tickets/ticket48295_test.py
b/dirsrvtests/tickets/ticket48295_test.py
new file mode 100644
index 0000000..13a7f88
--- /dev/null
+++ b/dirsrvtests/tickets/ticket48295_test.py
@@ -0,0 +1,212 @@
+# --- 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
+
+
+(a)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, revert):
+ try:
+ centry = topology.standalone.search_s(dn, ldap.SCOPE_BASE, 'uid=*')
+ if centry:
+ val = centry[0].getValue(attr)
+ if val:
+ if val.lower() == expected.lower():
+ if revert:
+ log.info('Value of %s %s exists, which should not.' %
(attr, expected))
+ assert False
+ else:
+ log.info('Value of %s is %s' % (attr, expected))
+ else:
+ if revert:
+ log.info('NEEDINFO: Value of %s is not %s, but %s' %
(attr, expected, val))
+ else:
+ log.info('Value of %s is not %s, but %s' % (attr,
expected, val))
+ assert False
+ else:
+ if revert:
+ log.info('Value of %s does not expectedly exist' % attr)
+ else:
+ log.info('Value of %s does not exist' % attr)
+ 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 _48295_init(topology):
+ """
+ Set up Linked Attribute
+ """
+ _header(topology, 'Testing Ticket 48295 - Entry cache is not rolled back --
Linked Attributes plug-in - wrong behaviour when adding valid and broken links')
+
+ 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('PASSED')
+
+
+def _48295_run(topology):
+ """
+ Add 2 linktypes - one exists, another does not
+ """
+
+ _header(topology, 'Add 2 linktypes to manager1 - one exists, another does not to
make sure the managed entry does not have managed type.')
+ try:
+ topology.standalone.modify_s('uid=manager1,%s' % OU_PEOPLE,
+ [(ldap.MOD_ADD, LINKTYPE, 'uid=employee1,%s'
% OU_PEOPLE),
+ (ldap.MOD_ADD, LINKTYPE,
'uid=doNotExist,%s' % OU_PEOPLE)])
+ except ldap.UNWILLING_TO_PERFORM:
+ log.info('Add uid=employee1 and uid=doNotExist expectedly failed.')
+ pass
+
+ log.info('Check managed attribute does not exist.')
+ check_attr_val(topology, 'uid=employee1,%s' % OU_PEOPLE, MANAGEDTYPE,
'uid=manager1,%s' % OU_PEOPLE, True)
+
+ log.info('PASSED')
+
+
+def _48295_final(topology):
+ topology.standalone.delete()
+ log.info('All PASSED')
+
+
+def test_ticket48295(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 '(a)pytest.fixture' line before
'topology' function.
+ - set the installation prefix
+ - run this program
+ '''
+ global installation_prefix
+ installation_prefix = None
+
+ _48295_init(topology)
+
+ _48295_run(topology)
+
+ _48295_final(topology)
+
+if __name__ == '__main__':
+ # Run isolated
+ # -s for DEBUG mode
+
+ CURRENT_FILE = os.path.realpath(__file__)
+ pytest.main("-s %s" % CURRENT_FILE)
commit 088ddec90957ca2ef7a1c072f8fe834eabf46298
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Mon Dec 21 16:33:34 2015 -0800
Ticket #48295 - Entry cache is not rolled back -- Linked Attributes plug-in - wrong
behaviour when adding valid and broken links
Bug Description: When multiple link attribute values are added or deleted
and if some of the op was successfully and one fails, the succeeded operation's
managed type appears in the managed entry although all of the link attribute
operation were rolled back. The managed type indeed does not exist in the
managed entry. That just in the entry cache. Once the server is restarted
the changes disappear.
Fix Description: If the first link attribute value operation fails, it stops
the operation and returns the failure. If the second or the later operation
fails, the succeeded operation up to the previous one are reverted.
https://fedorahosted.org/389/ticket/48295
Reviewed by mreynolds(a)redhat.com (Thank you, Mark!!)
diff --git a/ldap/servers/plugins/linkedattrs/linked_attrs.c
b/ldap/servers/plugins/linkedattrs/linked_attrs.c
index 0d07a1f..27af287 100644
--- a/ldap/servers/plugins/linkedattrs/linked_attrs.c
+++ b/ldap/servers/plugins/linkedattrs/linked_attrs.c
@@ -1474,6 +1474,9 @@ linked_attrs_mod_backpointers(Slapi_PBlock *pb, char *linkdn, char
*type,
} else if (rc != LDAP_SUCCESS) {
char *err_msg = NULL;
+ slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
+ "Linked Attrs Plugin: Failed to update link to
target entry (%s) error %d",
+ targetdn, rc);
err_msg = PR_smprintf("Linked Attrs Plugin: Failed to update "
"link to target entry (%s) error %d",
targetdn, rc);
@@ -1481,6 +1484,23 @@ linked_attrs_mod_backpointers(Slapi_PBlock *pb, char *linkdn, char
*type,
slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, err_msg);
PR_smprintf_free(err_msg);
slapi_sdn_free(&targetsdn);
+ if (i > 0) {
+ int j;
+ Slapi_ValueSet *undoVals = slapi_valueset_new();
+ /* undo 0..i-1 */
+ j = slapi_valueset_first_value(targetvals, &targetval);
+ do {
+ slapi_valueset_add_value(undoVals, targetval);
+ j = slapi_valueset_next_value(targetvals, j, &targetval);
+ } while (j < i);
+ if (LDAP_MOD_DELETE == modop) {
+ modop = LDAP_MOD_ADD;
+ } else {
+ modop = LDAP_MOD_DELETE;
+ }
+ rc = linked_attrs_mod_backpointers(pb, linkdn, type, scope, modop,
undoVals);
+ slapi_valueset_free(undoVals);
+ }
rc = LDAP_UNWILLING_TO_PERFORM;
break;
}