From 6205f87c065409851efb0275fb21b09fabc43e8a Mon Sep 17 00:00:00 2001
From: ugaston <ugaston@localhost>
Date: Mon, 14 Sep 2009 17:20:50 +0000
Subject: [PATCH] First set of External Changelog functional tests
---
opendj-sdk/opends/tests/staf-tests/shared/functions/ldap.xml | 323 +++++
opendj-sdk/opends/tests/staf-tests/shared/java/ldapjndi/modifyDn.java | 169 +++
opendj-sdk/opends/tests/staf-tests/functional-tests/testcases/replication/replication.xml | 1
opendj-sdk/opends/tests/staf-tests/shared/functions/utils.xml | 658 ++++++++++++
opendj-sdk/opends/tests/staf-tests/functional-tests/testcases/replication/externalchangelog/externalchangelog.xml | 2039 +++++++++++++++++++++++++++++++++++++
5 files changed, 3,185 insertions(+), 5 deletions(-)
diff --git a/opendj-sdk/opends/tests/staf-tests/functional-tests/testcases/replication/externalchangelog/externalchangelog.xml b/opendj-sdk/opends/tests/staf-tests/functional-tests/testcases/replication/externalchangelog/externalchangelog.xml
new file mode 100644
index 0000000..126a9a9
--- /dev/null
+++ b/opendj-sdk/opends/tests/staf-tests/functional-tests/testcases/replication/externalchangelog/externalchangelog.xml
@@ -0,0 +1,2039 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE stax SYSTEM "../../../../shared/stax.dtd">
+<!--
+ ! CDDL HEADER START
+ !
+ ! The contents of this file are subject to the terms of the
+ ! Common Development and Distribution License, Version 1.0 only
+ ! (the "License"). You may not use this file except in compliance
+ ! with the License.
+ !
+ ! You can obtain a copy of the license at
+ ! trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ ! or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ ! See the License for the specific language governing permissions
+ ! and limitations under the License.
+ !
+ ! When distributing Covered Code, include this CDDL HEADER in each
+ ! file and include the License file at
+ ! trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ ! add the following below this CDDL HEADER, with the fields enclosed
+ ! by brackets "[]" replaced with your own identifying information:
+ ! Portions Copyright [yyyy] [name of copyright owner]
+ !
+ ! CDDL HEADER END
+ !
+ ! Copyright 2008-2009 Sun Microsystems, Inc.
+ ! -->
+<stax>
+
+ <defaultcall function="replication_externalchangelog"/>
+
+ <function name="replication_externalchangelog">
+ <sequence>
+ <block name="'externalchangelog'">
+ <sequence>
+ <script>
+ if not CurrentTestPath.has_key('group'):
+ CurrentTestPath['group']='replication'
+ CurrentTestPath['suite']=STAXCurrentBlock
+ </script>
+
+ <call function="'testSuite_Preamble'"/>
+
+ <!--- Test Suite information
+ #@TestSuiteName Replication External Changelog Tests
+ #@TestSuitePurpose Test the event notification system provided by
+ the External Changelog.
+ #@TestSuiteID External Changelog Tests
+ #@TestSuiteGroup External Changelog
+ #@TestGroup Replication
+ #@TestScript replication_externalchangelog.xml
+ #@TestHTMLLink http://opends.dev.java.net/
+ -->
+
+ <import machine="STAF_LOCAL_HOSTNAME"
+ file="'%s/testcases/replication/replication_setup.xml'
+ % (TESTS_DIR)"/>
+ <call function="'replication_setup'">
+ { 'dataFile' : 'Example.ldif' }
+ </call>
+
+
+ <script>
+ # initialise the lastCookie value to that for the first ECL request
+ lastCookie = ';'
+ nextCookie = None
+
+ addOperationalAttrs = """\* creatorsname createtimestamp entryuuid"""
+ modOperationalAttrs = """\* modifiersname modifytimestamp entryuuid"""
+
+ class Entry:
+ def __init__(self, rdn):
+ self.userDn = '%s,ou=People,%s' \
+ % (rdn, synchroSuffix)
+ self.listAttr = []
+ self.listAttr.append('objectclass:top')
+ self.listAttr.append('objectclass:organizationalperson')
+ self.listAttr.append('objectclass:inetorgperson')
+ self.listAttr.append('objectclass:person')
+ def getDn(self):
+ return self.userDn
+ def getAttrList(self):
+ return self.listAttr
+ def addAttr(self, attrType, attrValue):
+ self.listAttr.append('%s:%s' % (attrType, attrValue))
+ </script>
+
+
+
+ <!--- Test Case information
+ #@TestMarker Replication External Changelog Tests
+ #@TestName Replication: External Changelog: Add_1
+ #@TestID Add_1
+ #@TestPurpose Verify add operation is recorded properly in the
+ external changelog on each replication server
+ #@TestPreamble
+ #@TestSteps Add entry to server A
+ #@TestSteps Verify servers in sync
+ #@TestSteps Read entry from ldap server
+ #@TestSteps Read last changelog entry on each repl server
+ #@TestSteps Check changelog entry against expected values
+ #@TestPostamble
+ #@TestResult Success if the server synchronised and the
+ changelog entry value check succeeds
+ -->
+ <testcase name="getTestCaseName('Add_1')">
+ <sequence>
+ <call function="'testCase_Preamble'"/>
+ <message>
+ 'Replication: External Changelog: Add_1. \
+ Verify add operation is recorded properly in the external \
+ changelog on each replication server'
+ </message>
+
+ <!-- Add entry to "master" server -->
+ <script>
+ myEntry = Entry('cn=a')
+ myEntry.addAttr('sn', 'a')
+ myEntry.addAttr('description', '1')
+ myEntry.addAttr('description', '2')
+ myEntry.addAttr('uid', 'A')
+
+ addedEntry = None
+ eclEntry = None
+ </script>
+ <call function="'addAnEntry'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'dsInstanceHost' : masterHost,
+ 'dsInstancePort' : master.getPort(),
+ 'dsInstanceDn' : master.getRootDn(),
+ 'dsInstancePswd' : master.getRootPwd(),
+ 'DNToAdd' : myEntry.getDn(),
+ 'listAttributes' : myEntry.getAttrList()
+ }
+ </call>
+
+ <!-- Verify the synchronization of the trees among the servers in
+ the topology -->
+ <call function="'verifyTrees'">
+ [ clientHost, clientPath, master, consumerList, synchroSuffix ]
+ </call>
+
+ <!-- Retrieve entry information for checkChangelogEntry's sake -->
+ <call function="'ldapSearchWithScript'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'dsInstanceHost' : masterHost,
+ 'dsInstancePort' : master.getPort(),
+ 'dsInstanceDn' : master.getRootDn(),
+ 'dsInstancePswd' : master.getRootPwd(),
+ 'dsBaseDN' : myEntry.getDn(),
+ 'dsFilter' : 'objectclass=*',
+ 'dsAttributes' : addOperationalAttrs
+ }
+ </call>
+ <script>
+ searchRC = STAXResult[0][0]
+ searchResult = STAXResult[0][1]
+ </script>
+
+ <if expr="searchRC == 0">
+ <sequence>
+ <message>
+ 'This is the entry as read from server %s:%s: \n%s' % \
+ (masterHost, master.getPort(), searchResult)
+ </message>
+ <call function="'parseLdifEntry'">
+ { 'ldifEntry' : searchResult }
+ </call>
+ <script>
+ addedEntry = STAXResult
+
+ myTargetDN = addedEntry['dn'][0]
+ myChangeType = 'add'
+ myChangeTime = addedEntry['createtimestamp'][0]
+ myTargetEntryUUID = addedEntry['entryuuid'][0]
+ # myReplicationCSN = ----> grab from where???
+ # myReplicatIdentifier = ----> grab from ldap server
+ myChanges = {}
+
+ for attr in addedEntry.keys():
+ if (attr != 'dn') and (attr != 'changelogcookie') :
+ myChanges[attr] = addedEntry[attr]
+ </script>
+ </sequence>
+ <else>
+ <message log="1" level="'Error'">
+ 'Could not read added entry %s from server %s:%s' % \
+ (myEntry.getDn(), masterHost, master.getPort())
+ </message>
+ </else>
+ </if>
+
+ <!-- Search changelog in the various replication servers -->
+ <iterate var="server"
+ in="_topologyServerList"
+ indexvar="i">
+ <sequence>
+ <script>
+ if globalSplitServers:
+ replServer = _topologyReplServerList[i]
+ else:
+ replServer = server
+
+ replServerPath = '%s/%s' % (replServer.getDir(), OPENDSNAME)
+ </script>
+
+ <message>
+ 'Reading changelog in replication server %s:%s from index: \
+ %s' % \
+ (replServer.getHostname(), replServer.getPort(), lastCookie)
+ </message>
+
+ <!-- Search for entry add -->
+ <call function="'SearchExternalChangelog'">
+ { 'location' : replServer.getHostname(),
+ 'dsPath' : replServerPath,
+ 'dsInstanceHost' : replServer.getHostname(),
+ 'dsInstancePort' : replServer.getPort(),
+ 'dsInstanceDn' : replServer.getRootDn(),
+ 'dsInstancePswd' : replServer.getRootPwd(),
+ 'dsScope' : 'subordinate',
+ 'dsBaseDN' : 'cn=changelog',
+ 'dsFilter' : '(objectclass=*)',
+ 'changelogCookie' : lastCookie
+ }
+ </call>
+ <script>
+ searchRC = STAXResult[0][0]
+ searchResult = STAXResult[0][1]
+ </script>
+ <if expr="searchRC == 0">
+ <sequence>
+ <message>
+ 'This is the ECL entry as read from server %s:%s: \n%s' %\
+ (replServer.getHostname(), replServer.getPort(),
+ searchResult)
+ </message>
+ <call function="'parseLdifEntry'">
+ { 'ldifEntry' : searchResult }
+ </call>
+ <script>
+ eclEntry = STAXResult
+
+ nextCookie = eclEntry['changelogcookie'][0]
+ </script>
+ <message>
+ 'Parsed changelog entry: \n%s' % eclEntry
+ </message>
+ <message>
+ 'Cookie to use for the next ECL search: %s' % \
+ nextCookie
+ </message>
+ </sequence>
+ <else>
+ <message log="1" level="'Error'">
+ 'Could not read changelog on replication server %s:%s' \
+ % (replServer.getHostname(), replServer.getPort())
+ </message>
+ </else>
+ </if>
+
+ <if expr="addedEntry and eclEntry">
+ <call function="'checkChangelogEntry'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'changelogEntry' : eclEntry,
+ 'targetDN' : myTargetDN,
+ 'changeType' : myChangeType,
+ 'changeTime' : myChangeTime,
+ 'targetEntryUUID' : myTargetEntryUUID,
+ 'changes' : myChanges
+ }
+ </call>
+ <else>
+ <sequence>
+ <message log="1" level="'Error'">
+ 'Unable to check external changelog entry (failed to \
+ read entries %s and/or %s)' % \
+ (myEntry.getDn(), eclEntry['dn'][0])
+ </message>
+ <call function="'testFailed'"/>
+ </sequence>
+ </else>
+ </if>
+
+ </sequence>
+ </iterate>
+
+ <script>
+ # set the lastCookie for the next ECL search
+ if nextCookie:
+ lastCookie = nextCookie
+
+ # reset variables, just in case
+ addedEntry = None
+ eclEntry = None
+ </script>
+
+ <call function="'testCase_Postamble'"/>
+ </sequence>
+ </testcase>
+
+
+
+ <!--- Test Case information
+ #@TestMarker Replication External Changelog Tests
+ #@TestName Replication: External Changelog: Modify_add
+ #@TestID Modify_add
+ #@TestPurpose Verify modify-add operation is recorded properly
+ in the external changelog on each repl server
+ #@TestPreamble
+ #@TestSteps Modify entry on server A
+ #@TestSteps Verify servers in sync
+ #@TestSteps Read entry from ldap server
+ #@TestSteps Read last changelog entry on each repl server
+ #@TestSteps Check changelog entry against expected values
+ #@TestPostamble
+ #@TestResult Success if the server synchronised and the
+ changelog entry value check succeeds
+ -->
+ <testcase name="getTestCaseName('Modify_add')">
+ <sequence>
+ <call function="'testCase_Preamble'"/>
+ <message>
+ 'Replication: External Changelog: Modify_add. \
+ Verify modify-add operation is recorded properly in the \
+ external changelog on each repl server'
+ </message>
+
+ <script>
+ modEntry = None
+ eclEntry = None
+ </script>
+
+ <!-- Modify entry on one of the servers -->
+ <call function="'modifyAnAttribute'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'dsInstanceHost' : masterHost,
+ 'dsInstancePort' : master.getPort(),
+ 'dsInstanceDn' : master.getRootDn(),
+ 'dsInstancePswd' : master.getRootPwd(),
+ 'DNToModify' : myEntry.getDn(),
+ 'attributeName' : 'description',
+ 'newAttributeValue' : '3',
+ 'changetype' : 'add'
+ }
+ </call>
+
+ <!-- Verify the synchronization of the trees among the servers in
+ the topology -->
+ <call function="'verifyTrees'">
+ [ clientHost, clientPath, master, consumerList, synchroSuffix ]
+ </call>
+
+ <!-- Retrieve entry information for checkChangelogEntry's sake -->
+ <call function="'ldapSearchWithScript'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'dsInstanceHost' : masterHost,
+ 'dsInstancePort' : master.getPort(),
+ 'dsInstanceDn' : master.getRootDn(),
+ 'dsInstancePswd' : master.getRootPwd(),
+ 'dsBaseDN' : myEntry.getDn(),
+ 'dsFilter' : 'objectclass=*',
+ 'dsAttributes' : modOperationalAttrs
+ }
+ </call>
+ <script>
+ searchRC = STAXResult[0][0]
+ searchResult = STAXResult[0][1]
+ </script>
+
+ <if expr="searchRC == 0">
+ <sequence>
+ <message>
+ 'This is the entry as read from server %s:%s: \n%s' % \
+ (masterHost, master.getPort(), searchResult)
+ </message>
+ <call function="'parseLdifEntry'">
+ { 'ldifEntry' : searchResult }
+ </call>
+ <script>
+ modEntry = STAXResult
+
+ myTargetDN = modEntry['dn'][0]
+ myChangeType = 'modify'
+ myChangeTime = modEntry['modifytimestamp'][0]
+ myTargetEntryUUID = modEntry['entryuuid'][0]
+ # myReplicationCSN = ----> grab from where???
+ # myReplicatIdentifier = ----> grab from ldap server
+ myModifiersName = modEntry['modifiersname'][0]
+ myModifyTimestamp = modEntry['modifytimestamp'][0]
+ myChanges = []
+ myChanges.append(['add', 'description', '3'])
+ myChanges.append(['replace', 'modifiersname', myModifiersName])
+ myChanges.append(['replace', 'modifytimestamp', myModifyTimestamp])
+ </script>
+ </sequence>
+ <else>
+ <message log="1" level="'Error'">
+ 'Could not read modified entry %s from server %s:%s' % \
+ (myEntry.getDn(), masterHost, master.getPort())
+ </message>
+ </else>
+ </if>
+
+ <!-- Search changelog in the various replication servers -->
+ <iterate var="server"
+ in="_topologyServerList"
+ indexvar="i">
+ <sequence>
+ <script>
+ if globalSplitServers:
+ replServer = _topologyReplServerList[i]
+ else:
+ replServer = server
+
+ replServerPath = '%s/%s' % (replServer.getDir(), OPENDSNAME)
+ </script>
+
+ <message>
+ 'Reading changelog in replication server %s:%s from index: \
+ %s' % \
+ (replServer.getHostname(), replServer.getPort(), lastCookie)
+ </message>
+
+ <!-- Search for entry modify -->
+ <call function="'SearchExternalChangelog'">
+ { 'location' : replServer.getHostname(),
+ 'dsPath' : replServerPath,
+ 'dsInstanceHost' : replServer.getHostname(),
+ 'dsInstancePort' : replServer.getPort(),
+ 'dsInstanceDn' : replServer.getRootDn(),
+ 'dsInstancePswd' : replServer.getRootPwd(),
+ 'dsScope' : 'subordinate',
+ 'dsBaseDN' : 'cn=changelog',
+ 'dsFilter' : '(objectclass=*)',
+ 'changelogCookie' : lastCookie
+ }
+ </call>
+ <script>
+ searchRC = STAXResult[0][0]
+ searchResult = STAXResult[0][1]
+ </script>
+ <if expr="searchRC == 0">
+ <sequence>
+ <message>
+ 'This is the ECL entry as read from server %s:%s: \n%s'\
+ % (replServer.getHostname(), replServer.getPort(),
+ searchResult)
+ </message>
+ <call function="'parseLdifEntry'">
+ { 'ldifEntry' : searchResult }
+ </call>
+ <script>
+ eclEntry = STAXResult
+
+ nextCookie = eclEntry['changelogcookie'][0]
+ </script>
+ <message>
+ 'Parsed changelog entry: \n%s' % eclEntry
+ </message>
+ <message>
+ 'Cookie to use for the next ECL search: %s' % \
+ nextCookie
+ </message>
+ </sequence>
+ <else>
+ <message log="1" level="'Error'">
+ 'Could not read changelog on replication server %s:%s' \
+ % (replServer.getHostname(), replServer.getPort())
+ </message>
+ </else>
+ </if>
+
+ <if expr="modEntry and eclEntry">
+ <call function="'checkChangelogEntry'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'changelogEntry' : eclEntry,
+ 'targetDN' : myTargetDN,
+ 'changeType' : myChangeType,
+ 'changeTime' : myChangeTime,
+ 'targetEntryUUID' : myTargetEntryUUID,
+ 'changes' : myChanges
+ }
+ </call>
+ <else>
+ <sequence>
+ <message log="1" level="'Error'">
+ 'Unable to check external changelog entry (failed to \
+ read entries %s and/or %s)' % \
+ (myEntry.getDn(), eclEntry['dn'][0])
+ </message>
+ <call function="'testFailed'"/>
+ </sequence>
+ </else>
+ </if>
+
+ </sequence>
+ </iterate>
+
+ <script>
+ # set the lastCookie for the next ECL search
+ if nextCookie:
+ lastCookie = nextCookie
+
+ # reset variables, just in case
+ modEntry = None
+ eclEntry = None
+ </script>
+
+ <call function="'testCase_Postamble'"/>
+ </sequence>
+ </testcase>
+
+
+ <!--- Test Case information
+ #@TestMarker Replication External Changelog Tests
+ #@TestName Replication: External Changelog: Modify_delete
+ #@TestID Modify_delete
+ #@TestPurpose Verify modify-del operation is recorded properly
+ in the external changelog on each repl server
+ #@TestPreamble
+ #@TestSteps Modify entry on server A
+ #@TestSteps Verify servers in sync
+ #@TestSteps Read entry from ldap server
+ #@TestSteps Read last changelog entry on each repl server
+ #@TestSteps Check changelog entry against expected values
+ #@TestPostamble
+ #@TestResult Success if the server synchronised and the
+ changelog entry value check succeeds
+ -->
+ <testcase name="getTestCaseName('Modify_delete')">
+ <sequence>
+ <call function="'testCase_Preamble'"/>
+ <message>
+ 'Replication: External Changelog: Modify_delete. \
+ Verify modify-del operation is recorded properly in the \
+ external changelog on each repl server'
+ </message>
+
+ <script>
+ modEntry = None
+ eclEntry = None
+
+ valuesToDelete = []
+ valuesToDelete.append('description:1')
+ </script>
+
+ <!-- Modify entry on one of the servers -->
+ <call function="'modifyAnAttribute'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'dsInstanceHost' : masterHost,
+ 'dsInstancePort' : master.getPort(),
+ 'dsInstanceDn' : master.getRootDn(),
+ 'dsInstancePswd' : master.getRootPwd(),
+ 'DNToModify' : myEntry.getDn(),
+ 'listAttributes' : valuesToDelete,
+ 'changetype' : 'delete'
+ }
+ </call>
+
+ <!-- Verify the synchronization of the trees among the servers in
+ the topology -->
+ <call function="'verifyTrees'">
+ [ clientHost, clientPath, master, consumerList, synchroSuffix ]
+ </call>
+
+ <!-- Retrieve entry information for checkChangelogEntry's sake -->
+ <call function="'ldapSearchWithScript'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'dsInstanceHost' : masterHost,
+ 'dsInstancePort' : master.getPort(),
+ 'dsInstanceDn' : master.getRootDn(),
+ 'dsInstancePswd' : master.getRootPwd(),
+ 'dsBaseDN' : myEntry.getDn(),
+ 'dsFilter' : 'objectclass=*',
+ 'dsAttributes' : modOperationalAttrs
+ }
+ </call>
+ <script>
+ searchRC = STAXResult[0][0]
+ searchResult = STAXResult[0][1]
+ </script>
+
+ <if expr="searchRC == 0">
+ <sequence>
+ <message>
+ 'This is the entry as read from server %s:%s: \n%s' % \
+ (masterHost, master.getPort(), searchResult)
+ </message>
+ <call function="'parseLdifEntry'">
+ { 'ldifEntry' : searchResult }
+ </call>
+ <script>
+ modEntry = STAXResult
+
+ myTargetDN = modEntry['dn'][0]
+ myChangeType = 'modify'
+ myChangeTime = modEntry['modifytimestamp'][0]
+ myTargetEntryUUID = modEntry['entryuuid'][0]
+ # myReplicationCSN = ----> grab from where???
+ # myReplicatIdentifier = ----> grab from ldap server
+ myModifiersName = modEntry['modifiersname'][0]
+ myModifyTimestamp = modEntry['modifytimestamp'][0]
+ myChanges = []
+ myChanges.append(['delete', 'description', '1'])
+ myChanges.append(['replace', 'modifiersname', myModifiersName])
+ myChanges.append(['replace', 'modifytimestamp', myModifyTimestamp])
+ </script>
+ </sequence>
+ <else>
+ <message log="1" level="'Error'">
+ 'Could not read modified entry %s from server %s:%s' % \
+ (myEntry.getDn(), masterHost, master.getPort())
+ </message>
+ </else>
+ </if>
+
+ <!-- Search changelog in the various replication servers -->
+ <iterate var="server"
+ in="_topologyServerList"
+ indexvar="i">
+ <sequence>
+ <script>
+ if globalSplitServers:
+ replServer = _topologyReplServerList[i]
+ else:
+ replServer = server
+
+ replServerPath = '%s/%s' % (replServer.getDir(), OPENDSNAME)
+ </script>
+
+ <message>
+ 'Reading changelog in replication server %s:%s from index: \
+ %s' % \
+ (replServer.getHostname(), replServer.getPort(), lastCookie)
+ </message>
+
+ <!-- Search for entry modify -->
+ <call function="'SearchExternalChangelog'">
+ { 'location' : replServer.getHostname(),
+ 'dsPath' : replServerPath,
+ 'dsInstanceHost' : replServer.getHostname(),
+ 'dsInstancePort' : replServer.getPort(),
+ 'dsInstanceDn' : replServer.getRootDn(),
+ 'dsInstancePswd' : replServer.getRootPwd(),
+ 'dsScope' : 'subordinate',
+ 'dsBaseDN' : 'cn=changelog',
+ 'dsFilter' : '(objectclass=*)',
+ 'changelogCookie' : lastCookie
+ }
+ </call>
+ <script>
+ searchRC = STAXResult[0][0]
+ searchResult = STAXResult[0][1]
+ </script>
+ <if expr="searchRC == 0">
+ <sequence>
+ <message>
+ 'This is the ECL entry as read from server %s:%s: \n%s'\
+ % (replServer.getHostname(), replServer.getPort(),
+ searchResult)
+ </message>
+ <call function="'parseLdifEntry'">
+ { 'ldifEntry' : searchResult }
+ </call>
+ <script>
+ eclEntry = STAXResult
+
+ nextCookie = eclEntry['changelogcookie'][0]
+ </script>
+ <message>
+ 'Parsed changelog entry: \n%s' % eclEntry
+ </message>
+ <message>
+ 'Cookie to use for the next ECL search: %s' % \
+ nextCookie
+ </message>
+ </sequence>
+ <else>
+ <message log="1" level="'Error'">
+ 'Could not read changelog on replication server %s:%s' \
+ % (replServer.getHostname(), replServer.getPort())
+ </message>
+ </else>
+ </if>
+
+ <if expr="modEntry and eclEntry">
+ <call function="'checkChangelogEntry'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'changelogEntry' : eclEntry,
+ 'targetDN' : myTargetDN,
+ 'changeType' : myChangeType,
+ 'changeTime' : myChangeTime,
+ 'targetEntryUUID' : myTargetEntryUUID,
+ 'changes' : myChanges
+ }
+ </call>
+ <else>
+ <sequence>
+ <message log="1" level="'Error'">
+ 'Unable to check external changelog entry (failed to \
+ read entries %s and/or %s)' % \
+ (myEntry.getDn(), eclEntry['dn'][0])
+ </message>
+ <call function="'testFailed'"/>
+ </sequence>
+ </else>
+ </if>
+
+ </sequence>
+ </iterate>
+
+ <script>
+ # set the lastCookie for the next ECL search
+ if nextCookie:
+ lastCookie = nextCookie
+
+ # reset variables, just in case
+ modEntry = None
+ eclEntry = None
+ </script>
+
+ <call function="'testCase_Postamble'"/>
+ </sequence>
+ </testcase>
+
+
+ <!--- Test Case information
+ #@TestMarker Replication External Changelog Tests
+ #@TestName Replication: External Changelog: Modify_replace
+ #@TestID Modify_replace
+ #@TestPurpose Verify modify-replace operation is well recorded
+ in the external changelog on each repl server
+ #@TestPreamble
+ #@TestSteps Modify entry on server A
+ #@TestSteps Verify servers in sync
+ #@TestSteps Read entry from ldap server
+ #@TestSteps Read last changelog entry on each repl server
+ #@TestSteps Check changelog entry against expected values
+ #@TestPostamble
+ #@TestResult Success if the server synchronised and the
+ changelog entry value check succeeds
+ -->
+ <testcase name="getTestCaseName('Modify_replace')">
+ <sequence>
+ <call function="'testCase_Preamble'"/>
+ <message>
+ 'Replication: External Changelog: Modify_replace. \
+ Verify modify-replace operation is recorded properly in the \
+ external changelog on each repl server'
+ </message>
+
+ <script>
+ modEntry = None
+ eclEntry = None
+ </script>
+
+ <!-- Modify entry on one of the servers -->
+ <call function="'modifyAnAttribute'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'dsInstanceHost' : masterHost,
+ 'dsInstancePort' : master.getPort(),
+ 'dsInstanceDn' : master.getRootDn(),
+ 'dsInstancePswd' : master.getRootPwd(),
+ 'DNToModify' : myEntry.getDn(),
+ 'attributeName' : 'description',
+ 'newAttributeValue' : 'new',
+ 'changetype' : 'replace'
+ }
+ </call>
+
+ <!-- Verify the synchronization of the trees among the servers in
+ the topology -->
+ <call function="'verifyTrees'">
+ [ clientHost, clientPath, master, consumerList, synchroSuffix ]
+ </call>
+
+ <!-- Retrieve entry information for checkChangelogEntry's sake -->
+ <call function="'ldapSearchWithScript'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'dsInstanceHost' : masterHost,
+ 'dsInstancePort' : master.getPort(),
+ 'dsInstanceDn' : master.getRootDn(),
+ 'dsInstancePswd' : master.getRootPwd(),
+ 'dsBaseDN' : myEntry.getDn(),
+ 'dsFilter' : 'objectclass=*',
+ 'dsAttributes' : modOperationalAttrs
+ }
+ </call>
+ <script>
+ searchRC = STAXResult[0][0]
+ searchResult = STAXResult[0][1]
+ </script>
+
+ <if expr="searchRC == 0">
+ <sequence>
+ <message>
+ 'This is the entry as read from server %s:%s: \n%s' % \
+ (masterHost, master.getPort(), searchResult)
+ </message>
+ <call function="'parseLdifEntry'">
+ { 'ldifEntry' : searchResult }
+ </call>
+ <script>
+ modEntry = STAXResult
+
+ myTargetDN = modEntry['dn'][0]
+ myChangeType = 'modify'
+ myChangeTime = modEntry['modifytimestamp'][0]
+ myTargetEntryUUID = modEntry['entryuuid'][0]
+ # myReplicationCSN = ----> grab from where???
+ # myReplicatIdentifier = ----> grab from ldap server
+ myModifiersName = modEntry['modifiersname'][0]
+ myModifyTimestamp = modEntry['modifytimestamp'][0]
+ myChanges = []
+ myChanges.append(['replace', 'description', 'new'])
+ myChanges.append(['replace', 'modifiersname', myModifiersName])
+ myChanges.append(['replace', 'modifytimestamp', myModifyTimestamp])
+ </script>
+ </sequence>
+ <else>
+ <message log="1" level="'Error'">
+ 'Could not read modified entry %s from server %s:%s' % \
+ (myEntry.getDn(), masterHost, master.getPort())
+ </message>
+ </else>
+ </if>
+
+ <!-- Search changelog in the various replication servers -->
+ <iterate var="server"
+ in="_topologyServerList"
+ indexvar="i">
+ <sequence>
+ <script>
+ if globalSplitServers:
+ replServer = _topologyReplServerList[i]
+ else:
+ replServer = server
+
+ replServerPath = '%s/%s' % (replServer.getDir(), OPENDSNAME)
+ </script>
+
+ <message>
+ 'Reading changelog in replication server %s:%s from index: \
+ %s' % \
+ (replServer.getHostname(), replServer.getPort(), lastCookie)
+ </message>
+
+ <!-- Search for entry modify -->
+ <call function="'SearchExternalChangelog'">
+ { 'location' : replServer.getHostname(),
+ 'dsPath' : replServerPath,
+ 'dsInstanceHost' : replServer.getHostname(),
+ 'dsInstancePort' : replServer.getPort(),
+ 'dsInstanceDn' : replServer.getRootDn(),
+ 'dsInstancePswd' : replServer.getRootPwd(),
+ 'dsScope' : 'subordinate',
+ 'dsBaseDN' : 'cn=changelog',
+ 'dsFilter' : '(objectclass=*)',
+ 'changelogCookie' : lastCookie
+ }
+ </call>
+ <script>
+ searchRC = STAXResult[0][0]
+ searchResult = STAXResult[0][1]
+ </script>
+ <if expr="searchRC == 0">
+ <sequence>
+ <message>
+ 'This is the ECL entry as read from server %s:%s: \n%s'\
+ % (replServer.getHostname(), replServer.getPort(),
+ searchResult)
+ </message>
+ <call function="'parseLdifEntry'">
+ { 'ldifEntry' : searchResult }
+ </call>
+ <script>
+ eclEntry = STAXResult
+
+ nextCookie = eclEntry['changelogcookie'][0]
+ </script>
+ <message>
+ 'Parsed changelog entry: \n%s' % eclEntry
+ </message>
+ <message>
+ 'Cookie to use for the next ECL search: %s' % \
+ nextCookie
+ </message>
+ </sequence>
+ <else>
+ <message log="1" level="'Error'">
+ 'Could not read changelog on replication server %s:%s' \
+ % (replServer.getHostname(), replServer.getPort())
+ </message>
+ </else>
+ </if>
+
+ <if expr="modEntry and eclEntry">
+ <call function="'checkChangelogEntry'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'changelogEntry' : eclEntry,
+ 'targetDN' : myTargetDN,
+ 'changeType' : myChangeType,
+ 'changeTime' : myChangeTime,
+ 'targetEntryUUID' : myTargetEntryUUID,
+ 'changes' : myChanges
+ }
+ </call>
+ <else>
+ <sequence>
+ <message log="1" level="'Error'">
+ 'Unable to check external changelog entry (failed to \
+ read entries %s and/or %s)' % \
+ (myEntry.getDn(), eclEntry['dn'][0])
+ </message>
+ <call function="'testFailed'"/>
+ </sequence>
+ </else>
+ </if>
+
+ </sequence>
+ </iterate>
+
+ <script>
+ # set the lastCookie for the next ECL search
+ if nextCookie:
+ lastCookie = nextCookie
+
+ # reset variables, just in case
+ modEntry = None
+ eclEntry = None
+ </script>
+
+ <call function="'testCase_Postamble'"/>
+ </sequence>
+ </testcase>
+
+
+ <!--- Test Case information
+ #@TestMarker Replication External Changelog Tests
+ #@TestName Replication: External Changelog: Modrdn_deleteoldrdn_true
+ #@TestID Modrdn_deleteoldrdn_true
+ #@TestPurpose Verify modrdn operation is recorded properly
+ in the external changelog on each repl server
+ #@TestPreamble
+ #@TestSteps Modrdn entry on server A
+ #@TestSteps Verify servers in sync
+ #@TestSteps Read entry from ldap server
+ #@TestSteps Read last changelog entry on each repl server
+ #@TestSteps Check changelog entry against expected values
+ #@TestPostamble
+ #@TestResult Success if the server synchronised and the
+ changelog entry value check succeeds
+ -->
+ <testcase name="getTestCaseName('Modrdn_deleteoldrdn_true')">
+ <sequence>
+ <call function="'testCase_Preamble'"/>
+ <message>
+ 'Replication: External Changelog: Modrdn_deleteoldrdn_true. \
+ Verify modrdn operation is recorded properly in the \
+ external changelog on each repl server'
+ </message>
+
+ <script>
+ modEntry = None
+ eclEntry = None
+
+ oldEntry = myEntry
+ newRdn = 'cn=b'
+ newEntry = Entry(newRdn)
+ </script>
+
+ <!-- Modify entry on one of the servers -->
+ <call function="'modifyDn'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'dsInstanceHost' : masterHost,
+ 'dsInstancePort' : master.getPort(),
+ 'dsInstanceDn' : master.getRootDn(),
+ 'dsInstancePswd' : master.getRootPwd(),
+ 'DNToModify' : oldEntry.getDn(),
+ 'newRDN' : newRdn
+ }
+ </call>
+
+ <!-- Verify the synchronization of the trees among the servers in
+ the topology -->
+ <call function="'verifyTrees'">
+ [ clientHost, clientPath, master, consumerList, synchroSuffix ]
+ </call>
+
+ <!-- Retrieve entry information for checkChangelogEntry's sake -->
+ <call function="'ldapSearchWithScript'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'dsInstanceHost' : masterHost,
+ 'dsInstancePort' : master.getPort(),
+ 'dsInstanceDn' : master.getRootDn(),
+ 'dsInstancePswd' : master.getRootPwd(),
+ 'dsBaseDN' : newEntry.getDn(),
+ 'dsFilter' : 'objectclass=*',
+ 'dsAttributes' : modOperationalAttrs
+ }
+ </call>
+ <script>
+ searchRC = STAXResult[0][0]
+ searchResult = STAXResult[0][1]
+ </script>
+
+ <if expr="searchRC == 0">
+ <sequence>
+ <message>
+ 'This is the entry as read from server %s:%s: \n%s' % \
+ (masterHost, master.getPort(), searchResult)
+ </message>
+ <call function="'parseLdifEntry'">
+ { 'ldifEntry' : searchResult }
+ </call>
+ <script>
+ modEntry = STAXResult
+
+ myTargetDN = oldEntry.getDn()
+ myChangeType = 'modrdn'
+ myChangeTime = modEntry['modifytimestamp'][0]
+ myTargetEntryUUID = modEntry['entryuuid'][0]
+ # myReplicationCSN = ----> grab from where???
+ # myReplicatIdentifier = ----> grab from ldap server
+ myNewRDN = newRdn
+ myDeleteOldRDN = 'true'
+ </script>
+ </sequence>
+ <else>
+ <message log="1" level="'Error'">
+ 'Could not read added entry %s from server %s:%s' % \
+ (newEntry.getDn(), masterHost, master.getPort())
+ </message>
+ </else>
+ </if>
+
+ <!-- Search changelog in the various replication servers -->
+ <iterate var="server"
+ in="_topologyServerList"
+ indexvar="i">
+ <sequence>
+ <script>
+ if globalSplitServers:
+ replServer = _topologyReplServerList[i]
+ else:
+ replServer = server
+
+ replServerPath = '%s/%s' % (replServer.getDir(), OPENDSNAME)
+ </script>
+
+ <message>
+ 'Reading changelog in replication server %s:%s from index: \
+ %s' % \
+ (replServer.getHostname(), replServer.getPort(), lastCookie)
+ </message>
+
+ <!-- Search for entry modify -->
+ <call function="'SearchExternalChangelog'">
+ { 'location' : replServer.getHostname(),
+ 'dsPath' : replServerPath,
+ 'dsInstanceHost' : replServer.getHostname(),
+ 'dsInstancePort' : replServer.getPort(),
+ 'dsInstanceDn' : replServer.getRootDn(),
+ 'dsInstancePswd' : replServer.getRootPwd(),
+ 'dsScope' : 'subordinate',
+ 'dsBaseDN' : 'cn=changelog',
+ 'dsFilter' : '(objectclass=*)',
+ 'changelogCookie' : lastCookie
+ }
+ </call>
+ <script>
+ searchRC = STAXResult[0][0]
+ searchResult = STAXResult[0][1]
+ </script>
+ <if expr="searchRC == 0">
+ <sequence>
+ <message>
+ 'This is the ECL entry as read from server %s:%s: \n%s'\
+ % (replServer.getHostname(), replServer.getPort(),
+ searchResult)
+ </message>
+ <call function="'parseLdifEntry'">
+ { 'ldifEntry' : searchResult }
+ </call>
+ <script>
+ eclEntry = STAXResult
+
+ nextCookie = eclEntry['changelogcookie'][0]
+ </script>
+ <message>
+ 'Parsed changelog entry: \n%s' % eclEntry
+ </message>
+ <message>
+ 'Cookie to use for the next ECL search: %s' % \
+ nextCookie
+ </message>
+ </sequence>
+ <else>
+ <message log="1" level="'Error'">
+ 'Could not read changelog on replication server %s:%s' \
+ % (replServer.getHostname(), replServer.getPort())
+ </message>
+ </else>
+ </if>
+
+ <if expr="modEntry and eclEntry">
+ <call function="'checkChangelogEntry'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'changelogEntry' : eclEntry,
+ 'targetDN' : myTargetDN,
+ 'changeType' : myChangeType,
+ 'changeTime' : myChangeTime,
+ 'targetEntryUUID' : myTargetEntryUUID,
+ 'newRDN' : myNewRDN,
+ 'deleteOldRDN' : myDeleteOldRDN
+ }
+ </call>
+ <else>
+ <sequence>
+ <message log="1" level="'Error'">
+ 'Unable to check external changelog entry (failed to \
+ read entries %s and/or %s)' % \
+ (newEntry.getDn(), eclEntry['dn'][0])
+ </message>
+ <call function="'testFailed'"/>
+ </sequence>
+ </else>
+ </if>
+
+ </sequence>
+ </iterate>
+
+ <script>
+ # set the lastCookie for the next ECL search
+ if nextCookie:
+ lastCookie = nextCookie
+
+ # reset variables, just in case
+ modEntry = None
+ eclEntry = None
+ </script>
+
+ <call function="'testCase_Postamble'"/>
+ </sequence>
+ </testcase>
+
+
+
+ <!--- Test Case information
+ #@TestMarker Replication External Changelog Tests
+ #@TestName Replication: External Changelog: Modrdn_deleteoldrdn_false
+ #@TestID Modrdn_deleteoldrdn_false
+ #@TestPurpose Verify modrdn operation is recorded properly
+ in the external changelog on each repl server
+ #@TestPreamble
+ #@TestSteps Modrdn entry on server A
+ #@TestSteps Verify servers in sync
+ #@TestSteps Read entry from ldap server
+ #@TestSteps Read last changelog entry on each repl server
+ #@TestSteps Check changelog entry against expected values
+ #@TestPostamble
+ #@TestResult Success if the server synchronised and the
+ changelog entry value check succeeds
+ -->
+ <testcase name="getTestCaseName('Modrdn_deleteoldrdn_false')">
+ <sequence>
+ <call function="'testCase_Preamble'"/>
+ <message>
+ 'Replication: External Changelog: Modrdn_deleteoldrdn_false. \
+ Verify modrdn operation is recorded properly in the \
+ external changelog on each repl server'
+ </message>
+
+ <script>
+ modEntry = None
+ eclEntry = None
+
+ oldEntry = newEntry
+ newRdn = 'cn=c'
+ newEntry = Entry(newRdn)
+ </script>
+
+ <!-- Modify entry on one of the servers -->
+ <call function="'modifyDn'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'dsInstanceHost' : masterHost,
+ 'dsInstancePort' : master.getPort(),
+ 'dsInstanceDn' : master.getRootDn(),
+ 'dsInstancePswd' : master.getRootPwd(),
+ 'DNToModify' : oldEntry.getDn(),
+ 'newRDN' : newRdn,
+ 'deleteOldRDN' : 0
+ }
+ </call>
+
+ <!-- Verify the synchronization of the trees among the servers in
+ the topology -->
+ <call function="'verifyTrees'">
+ [ clientHost, clientPath, master, consumerList, synchroSuffix ]
+ </call>
+
+ <!-- Retrieve entry information for checkChangelogEntry's sake -->
+ <call function="'ldapSearchWithScript'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'dsInstanceHost' : masterHost,
+ 'dsInstancePort' : master.getPort(),
+ 'dsInstanceDn' : master.getRootDn(),
+ 'dsInstancePswd' : master.getRootPwd(),
+ 'dsBaseDN' : newEntry.getDn(),
+ 'dsFilter' : 'objectclass=*',
+ 'dsAttributes' : modOperationalAttrs
+ }
+ </call>
+ <script>
+ searchRC = STAXResult[0][0]
+ searchResult = STAXResult[0][1]
+ </script>
+
+ <if expr="searchRC == 0">
+ <sequence>
+ <message>
+ 'This is the entry as read from server %s:%s: \n%s' % \
+ (masterHost, master.getPort(), searchResult)
+ </message>
+ <call function="'parseLdifEntry'">
+ { 'ldifEntry' : searchResult }
+ </call>
+ <script>
+ modEntry = STAXResult
+
+ myTargetDN = oldEntry.getDn()
+ myChangeType = 'modrdn'
+ myChangeTime = modEntry['modifytimestamp'][0]
+ myTargetEntryUUID = modEntry['entryuuid'][0]
+ # myReplicationCSN = ----> grab from where???
+ # myReplicatIdentifier = ----> grab from ldap server
+ myNewRDN = newRdn
+ myDeleteOldRDN = 'false'
+ </script>
+ </sequence>
+ <else>
+ <message log="1" level="'Error'">
+ 'Could not read added entry %s from server %s:%s' % \
+ (newEntry.getDn(), masterHost, master.getPort())
+ </message>
+ </else>
+ </if>
+
+ <!-- Search changelog in the various replication servers -->
+ <iterate var="server"
+ in="_topologyServerList"
+ indexvar="i">
+ <sequence>
+ <script>
+ if globalSplitServers:
+ replServer = _topologyReplServerList[i]
+ else:
+ replServer = server
+
+ replServerPath = '%s/%s' % (replServer.getDir(), OPENDSNAME)
+ </script>
+
+ <message>
+ 'Reading changelog in replication server %s:%s from index: \
+ %s' % \
+ (replServer.getHostname(), replServer.getPort(), lastCookie)
+ </message>
+
+ <!-- Search for entry modify -->
+ <call function="'SearchExternalChangelog'">
+ { 'location' : replServer.getHostname(),
+ 'dsPath' : replServerPath,
+ 'dsInstanceHost' : replServer.getHostname(),
+ 'dsInstancePort' : replServer.getPort(),
+ 'dsInstanceDn' : replServer.getRootDn(),
+ 'dsInstancePswd' : replServer.getRootPwd(),
+ 'dsScope' : 'subordinate',
+ 'dsBaseDN' : 'cn=changelog',
+ 'dsFilter' : '(objectclass=*)',
+ 'changelogCookie' : lastCookie
+ }
+ </call>
+ <script>
+ searchRC = STAXResult[0][0]
+ searchResult = STAXResult[0][1]
+ </script>
+ <if expr="searchRC == 0">
+ <sequence>
+ <message>
+ 'This is the ECL entry as read from server %s:%s: \n%s'\
+ % (replServer.getHostname(), replServer.getPort(),
+ searchResult)
+ </message>
+ <call function="'parseLdifEntry'">
+ { 'ldifEntry' : searchResult }
+ </call>
+ <script>
+ eclEntry = STAXResult
+
+ nextCookie = eclEntry['changelogcookie'][0]
+ </script>
+ <message>
+ 'Parsed changelog entry: \n%s' % eclEntry
+ </message>
+ <message>
+ 'Cookie to use for the next ECL search: %s' % \
+ nextCookie
+ </message>
+ </sequence>
+ <else>
+ <message log="1" level="'Error'">
+ 'Could not read changelog on replication server %s:%s' \
+ % (replServer.getHostname(), replServer.getPort())
+ </message>
+ </else>
+ </if>
+
+ <if expr="modEntry and eclEntry">
+ <call function="'checkChangelogEntry'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'changelogEntry' : eclEntry,
+ 'targetDN' : myTargetDN,
+ 'changeType' : myChangeType,
+ 'changeTime' : myChangeTime,
+ 'targetEntryUUID' : myTargetEntryUUID,
+ 'newRDN' : myNewRDN,
+ 'deleteOldRDN' : myDeleteOldRDN
+ }
+ </call>
+ <else>
+ <sequence>
+ <message log="1" level="'Error'">
+ 'Unable to check external changelog entry (failed to \
+ read entries %s and/or %s)' % \
+ (newEntry.getDn(), eclEntry['dn'][0])
+ </message>
+ <call function="'testFailed'"/>
+ </sequence>
+ </else>
+ </if>
+
+ </sequence>
+ </iterate>
+
+ <script>
+ # set the lastCookie for the next ECL search
+ if nextCookie:
+ lastCookie = nextCookie
+
+ # reset variables, just in case
+ modEntry = None
+ eclEntry = None
+ </script>
+
+ <call function="'testCase_Postamble'"/>
+ </sequence>
+ </testcase>
+
+
+ <!--- Test Case information
+ #@TestMarker Replication External Changelog Tests
+ #@TestName Replication: External Changelog: Delete_1
+ #@TestID Delete_1
+ #@TestPurpose Verify delete operation is recorded properly
+ in the external changelog on each repl server
+ #@TestPreamble
+ #@TestSteps Delete entry on server A
+ #@TestSteps Verify servers in sync
+ #@TestSteps Read entry from ldap server
+ #@TestSteps Read last changelog entry on each repl server
+ #@TestSteps Check changelog entry against expected values
+ #@TestPostamble
+ #@TestResult Success if the server synchronised and the
+ changelog entry value check succeeds
+ -->
+ <testcase name="getTestCaseName('Delete_1')">
+ <sequence>
+ <call function="'testCase_Preamble'"/>
+ <message>
+ 'Replication: External Changelog: Delete_1. \
+ Verify delete operation is recorded properly in the \
+ external changelog on each repl server'
+ </message>
+
+ <script>
+ delEntry = None
+ eclEntry = None
+ </script>
+
+ <!-- Retrieve entry information for checkChangelogEntry's sake -->
+ <call function="'ldapSearchWithScript'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'dsInstanceHost' : masterHost,
+ 'dsInstancePort' : master.getPort(),
+ 'dsInstanceDn' : master.getRootDn(),
+ 'dsInstancePswd' : master.getRootPwd(),
+ 'dsBaseDN' : newEntry.getDn(),
+ 'dsFilter' : 'objectclass=*',
+ 'dsAttributes' : modOperationalAttrs
+ }
+ </call>
+ <script>
+ searchRC = STAXResult[0][0]
+ searchResult = STAXResult[0][1]
+ </script>
+
+ <if expr="searchRC == 0">
+ <sequence>
+ <message>
+ 'This is the entry as read from server %s:%s: \n%s' % \
+ (masterHost, master.getPort(), searchResult)
+ </message>
+ <call function="'parseLdifEntry'">
+ { 'ldifEntry' : searchResult }
+ </call>
+ <script>
+ delEntry = STAXResult
+
+ myTargetDN = delEntry['dn'][0]
+ myChangeType = 'delete'
+ myTargetEntryUUID = delEntry['entryuuid'][0]
+ # myReplicationCSN = ----> grab from where???
+ # myReplicatIdentifier = ----> grab from ldap server
+ </script>
+ </sequence>
+ <else>
+ <message log="1" level="'Error'">
+ 'Could not read added entry %s from server %s:%s' % \
+ (newEntry.getDn(), masterHost, master.getPort())
+ </message>
+ </else>
+ </if>
+
+ <!-- Delete entry on one of the servers -->
+ <call function="'DeleteEntry'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'dsInstanceHost' : masterHost,
+ 'dsInstancePort' : master.getPort(),
+ 'dsInstanceDn' : master.getRootDn(),
+ 'dsInstancePswd' : master.getRootPwd(),
+ 'dsBaseDN' : newEntry.getDn()
+ }
+ </call>
+
+ <!-- Check delete worked on "master" server -->
+ <call function="'ldapSearchWithScript'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'dsInstanceHost' : masterHost,
+ 'dsInstancePort' : master.getPort(),
+ 'dsInstanceDn' : master.getRootDn(),
+ 'dsInstancePswd' : master.getRootPwd(),
+ 'dsBaseDN' : newEntry.getDn(),
+ 'dsFilter' : 'objectclass=*',
+ 'expectedRC' : 32
+ }
+ </call>
+
+ <!-- Verify the synchronization of the trees among the servers in
+ the topology -->
+ <call function="'verifyTrees'">
+ [ clientHost, clientPath, master, consumerList, synchroSuffix ]
+ </call>
+
+ <!-- Search changelog in the various replication servers -->
+ <iterate var="server"
+ in="_topologyServerList"
+ indexvar="i">
+ <sequence>
+ <script>
+ if globalSplitServers:
+ replServer = _topologyReplServerList[i]
+ else:
+ replServer = server
+
+ replServerPath = '%s/%s' % (replServer.getDir(), OPENDSNAME)
+ </script>
+
+ <message>
+ 'Reading changelog in replication server %s:%s from index: \
+ %s' % \
+ (replServer.getHostname(), replServer.getPort(), lastCookie)
+ </message>
+
+ <!-- Search for entry modify -->
+ <call function="'SearchExternalChangelog'">
+ { 'location' : replServer.getHostname(),
+ 'dsPath' : replServerPath,
+ 'dsInstanceHost' : replServer.getHostname(),
+ 'dsInstancePort' : replServer.getPort(),
+ 'dsInstanceDn' : replServer.getRootDn(),
+ 'dsInstancePswd' : replServer.getRootPwd(),
+ 'dsScope' : 'subordinate',
+ 'dsBaseDN' : 'cn=changelog',
+ 'dsFilter' : '(objectclass=*)',
+ 'changelogCookie' : lastCookie
+ }
+ </call>
+ <script>
+ searchRC = STAXResult[0][0]
+ searchResult = STAXResult[0][1]
+ </script>
+ <if expr="searchRC == 0">
+ <sequence>
+ <message>
+ 'This is the ECL entry as read from server %s:%s: \n%s'\
+ % (replServer.getHostname(), replServer.getPort(),
+ searchResult)
+ </message>
+ <call function="'parseLdifEntry'">
+ { 'ldifEntry' : searchResult }
+ </call>
+ <script>
+ eclEntry = STAXResult
+
+ nextCookie = eclEntry['changelogcookie'][0]
+ </script>
+ <message>
+ 'Parsed changelog entry: \n%s' % eclEntry
+ </message>
+ <message>
+ 'Cookie to use for the next ECL search: %s' % \
+ nextCookie
+ </message>
+ </sequence>
+ <else>
+ <message log="1" level="'Error'">
+ 'Could not read changelog on replication server %s:%s' \
+ % (replServer.getHostname(), replServer.getPort())
+ </message>
+ </else>
+ </if>
+
+ <if expr="delEntry and eclEntry">
+ <call function="'checkChangelogEntry'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'changelogEntry' : eclEntry,
+ 'targetDN' : myTargetDN,
+ 'changeType' : myChangeType,
+ 'targetEntryUUID' : myTargetEntryUUID
+ }
+ </call>
+ <else>
+ <sequence>
+ <message log="1" level="'Error'">
+ 'Unable to check external changelog entry (failed to \
+ read entries %s and/or %s)' % \
+ (newEntry.getDn(), eclEntry['dn'][0])
+ </message>
+ <call function="'testFailed'"/>
+ </sequence>
+ </else>
+ </if>
+
+ </sequence>
+ </iterate>
+
+ <script>
+ # set the lastCookie for the next ECL search
+ if nextCookie:
+ lastCookie = nextCookie
+
+ # reset variables, just in case
+ delEntry = None
+ eclEntry = None
+ </script>
+
+ <call function="'testCase_Postamble'"/>
+ </sequence>
+ </testcase>
+
+
+ <!--- Test Case information
+ #@TestMarker Replication External Changelog Tests
+ #@TestName Replication: External Changelog: Add_2
+ #@TestID Add_2
+ #@TestPurpose Verify add operation (of an entry with
+ userpassword) is recorded properly in the
+ external changelog on each replication server
+ #@TestPreamble
+ #@TestSteps Add entry to server A (with userpassword)
+ #@TestSteps Verify servers in sync
+ #@TestSteps Read entry from ldap server
+ #@TestSteps Read last changelog entry on each repl server
+ #@TestSteps Check changelog entry against expected values
+ #@TestPostamble
+ #@TestResult Success if the server synchronised and the
+ changelog entry value check succeeds
+ -->
+ <testcase name="getTestCaseName('Add_2')">
+ <sequence>
+ <call function="'testCase_Preamble'"/>
+ <message>
+ 'Replication: External Changelog: Add_2. \
+ Verify add operation (of and entry with userpassword) is \
+ recorded properly in the external changelog on each \
+ replication server'
+ </message>
+
+ <!-- Add entry to "master" server -->
+ <script>
+ myEntry = Entry('cn=user')
+ myEntry.addAttr('sn', 'user')
+ myEntry.addAttr('userpassword', 'password')
+
+ addedEntry = None
+ eclEntry = None
+ </script>
+ <call function="'addAnEntry'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'dsInstanceHost' : masterHost,
+ 'dsInstancePort' : master.getPort(),
+ 'dsInstanceDn' : master.getRootDn(),
+ 'dsInstancePswd' : master.getRootPwd(),
+ 'DNToAdd' : myEntry.getDn(),
+ 'listAttributes' : myEntry.getAttrList()
+ }
+ </call>
+
+ <!-- Verify the synchronization of the trees among the servers in
+ the topology -->
+ <call function="'verifyTrees'">
+ [ clientHost, clientPath, master, consumerList, synchroSuffix ]
+ </call>
+
+ <!-- Retrieve entry information for checkChangelogEntry's sake -->
+ <call function="'ldapSearchWithScript'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'dsInstanceHost' : masterHost,
+ 'dsInstancePort' : master.getPort(),
+ 'dsInstanceDn' : master.getRootDn(),
+ 'dsInstancePswd' : master.getRootPwd(),
+ 'dsBaseDN' : myEntry.getDn(),
+ 'dsFilter' : 'objectclass=*',
+ 'dsAttributes' : '%s pwdChangedTime' % addOperationalAttrs
+ }
+ </call>
+ <script>
+ searchRC = STAXResult[0][0]
+ searchResult = STAXResult[0][1]
+ </script>
+
+ <if expr="searchRC == 0">
+ <sequence>
+ <message>
+ 'This is the entry as read from server %s:%s: \n%s' % \
+ (masterHost, master.getPort(), searchResult)
+ </message>
+ <call function="'parseLdifEntry'">
+ { 'ldifEntry' : searchResult }
+ </call>
+ <script>
+ addedEntry = STAXResult
+
+ myTargetDN = addedEntry['dn'][0]
+ myChangeType = 'add'
+ myChangeTime = addedEntry['createtimestamp'][0]
+ myTargetEntryUUID = addedEntry['entryuuid'][0]
+ # myReplicationCSN = ----> grab from where???
+ # myReplicatIdentifier = ----> grab from ldap server
+ myChanges = {}
+
+ for attr in addedEntry.keys():
+ if (attr != 'dn') and (attr != 'changelogcookie') :
+ myChanges[attr] = addedEntry[attr]
+ </script>
+ </sequence>
+ <else>
+ <message log="1" level="'Error'">
+ 'Could not read added entry %s from server %s:%s' % \
+ (myEntry.getDn(), masterHost, master.getPort())
+ </message>
+ </else>
+ </if>
+
+ <!-- Search changelog in the various replication servers -->
+ <iterate var="server"
+ in="_topologyServerList"
+ indexvar="i">
+ <sequence>
+ <script>
+ if globalSplitServers:
+ replServer = _topologyReplServerList[i]
+ else:
+ replServer = server
+
+ replServerPath = '%s/%s' % (replServer.getDir(), OPENDSNAME)
+ </script>
+
+ <message>
+ 'Reading changelog in replication server %s:%s from index: \
+ %s' % \
+ (replServer.getHostname(), replServer.getPort(), lastCookie)
+ </message>
+
+ <!-- Search for entry add -->
+ <call function="'SearchExternalChangelog'">
+ { 'location' : replServer.getHostname(),
+ 'dsPath' : replServerPath,
+ 'dsInstanceHost' : replServer.getHostname(),
+ 'dsInstancePort' : replServer.getPort(),
+ 'dsInstanceDn' : replServer.getRootDn(),
+ 'dsInstancePswd' : replServer.getRootPwd(),
+ 'dsScope' : 'subordinate',
+ 'dsBaseDN' : 'cn=changelog',
+ 'dsFilter' : '(objectclass=*)',
+ 'changelogCookie' : lastCookie
+ }
+ </call>
+ <script>
+ searchRC = STAXResult[0][0]
+ searchResult = STAXResult[0][1]
+ </script>
+ <if expr="searchRC == 0">
+ <sequence>
+ <message>
+ 'This is the ECL entry as read from server %s:%s: \n%s' %\
+ (replServer.getHostname(), replServer.getPort(),
+ searchResult)
+ </message>
+ <call function="'parseLdifEntry'">
+ { 'ldifEntry' : searchResult }
+ </call>
+ <script>
+ eclEntry = STAXResult
+
+ nextCookie = eclEntry['changelogcookie'][0]
+ </script>
+ <message>
+ 'Parsed changelog entry: \n%s' % eclEntry
+ </message>
+ <message>
+ 'Cookie to use for the next ECL search: %s' % \
+ nextCookie
+ </message>
+ </sequence>
+ <else>
+ <message log="1" level="'Error'">
+ 'Could not read changelog on replication server %s:%s' \
+ % (replServer.getHostname(), replServer.getPort())
+ </message>
+ </else>
+ </if>
+
+ <if expr="addedEntry and eclEntry">
+ <call function="'checkChangelogEntry'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'changelogEntry' : eclEntry,
+ 'targetDN' : myTargetDN,
+ 'changeType' : myChangeType,
+ 'changeTime' : myChangeTime,
+ 'targetEntryUUID' : myTargetEntryUUID,
+ 'changes' : myChanges
+ }
+ </call>
+ <else>
+ <sequence>
+ <message log="1" level="'Error'">
+ 'Unable to check external changelog entry (failed to \
+ read entries %s and/or %s)' % \
+ (myEntry.getDn(), eclEntry['dn'][0])
+ </message>
+ <call function="'testFailed'"/>
+ </sequence>
+ </else>
+ </if>
+
+ </sequence>
+ </iterate>
+
+ <script>
+ # set the lastCookie for the next ECL search
+ if nextCookie:
+ lastCookie = nextCookie
+
+ # reset variables, just in case
+ addedEntry = None
+ eclEntry = None
+ </script>
+
+ <call function="'testCase_Postamble'"/>
+ </sequence>
+ </testcase>
+
+
+ <!--- Test Case information
+ #@TestMarker Replication External Changelog Tests
+ #@TestName Replication: External Changelog: Modify_replace_2
+ #@TestID Modify_replace_2
+ #@TestPurpose Verify modify-replace operation as non directory
+ manager is well recorded in the external
+ changelog on each repl server
+ #@TestPreamble
+ #@TestSteps Modify entry on server A (as non dir manager)
+ #@TestSteps Verify servers in sync
+ #@TestSteps Read entry from ldap server
+ #@TestSteps Read last changelog entry on each repl server
+ #@TestSteps Check changelog entry against expected values
+ #@TestPostamble
+ #@TestResult Success if the server synchronised and the
+ changelog entry value check succeeds
+ -->
+ <testcase name="getTestCaseName('Modify_replace_2')">
+ <sequence>
+ <call function="'testCase_Preamble'"/>
+ <message>
+ 'Replication: External Changelog: Modify_replace_2. \
+ Verify modify-replace operation as non directory manager is \
+ recorded properly in the external changelog on each repl server'
+ </message>
+
+ <script>
+ modEntry = None
+ eclEntry = None
+ </script>
+
+ <!-- Modify entry on one of the servers -->
+ <call function="'modifyAnAttribute'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'dsInstanceHost' : masterHost,
+ 'dsInstancePort' : master.getPort(),
+ 'dsInstanceDn' : myEntry.getDn(),
+ 'dsInstancePswd' : 'password',
+ 'DNToModify' : myEntry.getDn(),
+ 'attributeName' : 'userpassword',
+ 'newAttributeValue' : 'newpass',
+ 'changetype' : 'replace'
+ }
+ </call>
+
+ <!-- Verify the synchronization of the trees among the servers in
+ the topology -->
+ <call function="'verifyTrees'">
+ [ clientHost, clientPath, master, consumerList, synchroSuffix ]
+ </call>
+
+ <!-- Retrieve entry information for checkChangelogEntry's sake -->
+ <call function="'ldapSearchWithScript'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'dsInstanceHost' : masterHost,
+ 'dsInstancePort' : master.getPort(),
+ 'dsInstanceDn' : master.getRootDn(),
+ 'dsInstancePswd' : master.getRootPwd(),
+ 'dsBaseDN' : myEntry.getDn(),
+ 'dsFilter' : 'objectclass=*',
+ 'dsAttributes' : '%s pwdChangedTime' % modOperationalAttrs
+ }
+ </call>
+ <script>
+ searchRC = STAXResult[0][0]
+ searchResult = STAXResult[0][1]
+ </script>
+
+ <if expr="searchRC == 0">
+ <sequence>
+ <message>
+ 'This is the entry as read from server %s:%s: \n%s' % \
+ (masterHost, master.getPort(), searchResult)
+ </message>
+ <call function="'parseLdifEntry'">
+ { 'ldifEntry' : searchResult }
+ </call>
+ <script>
+ modEntry = STAXResult
+
+ myTargetDN = modEntry['dn'][0]
+ myChangeType = 'modify'
+ myChangeTime = modEntry['modifytimestamp'][0]
+ myTargetEntryUUID = modEntry['entryuuid'][0]
+ # myReplicationCSN = ----> grab from where???
+ # myReplicatIdentifier = ----> grab from ldap server
+ myModifiersName = modEntry['modifiersname'][0]
+ myModifyTimestamp = modEntry['modifytimestamp'][0]
+ myUserPassword = modEntry['userpassword'][0]
+ myPwdChangedTime = modEntry['pwdchangedtime'][0]
+ myChanges = []
+ myChanges.append(['replace', 'userpassword', myUserPassword])
+ myChanges.append(['replace', 'pwdchangedtime', myPwdChangedTime])
+ myChanges.append(['replace', 'modifiersname', myModifiersName])
+ myChanges.append(['replace', 'modifytimestamp', myModifyTimestamp])
+ </script>
+ </sequence>
+ <else>
+ <message log="1" level="'Error'">
+ 'Could not read modified entry %s from server %s:%s' % \
+ (myEntry.getDn(), masterHost, master.getPort())
+ </message>
+ </else>
+ </if>
+
+ <!-- Search changelog in the various replication servers -->
+ <iterate var="server"
+ in="_topologyServerList"
+ indexvar="i">
+ <sequence>
+ <script>
+ if globalSplitServers:
+ replServer = _topologyReplServerList[i]
+ else:
+ replServer = server
+
+ replServerPath = '%s/%s' % (replServer.getDir(), OPENDSNAME)
+ </script>
+
+ <message>
+ 'Reading changelog in replication server %s:%s from index: \
+ %s' % \
+ (replServer.getHostname(), replServer.getPort(), lastCookie)
+ </message>
+
+ <!-- Search for entry modify -->
+ <call function="'SearchExternalChangelog'">
+ { 'location' : replServer.getHostname(),
+ 'dsPath' : replServerPath,
+ 'dsInstanceHost' : replServer.getHostname(),
+ 'dsInstancePort' : replServer.getPort(),
+ 'dsInstanceDn' : replServer.getRootDn(),
+ 'dsInstancePswd' : replServer.getRootPwd(),
+ 'dsScope' : 'subordinate',
+ 'dsBaseDN' : 'cn=changelog',
+ 'dsFilter' : '(objectclass=*)',
+ 'changelogCookie' : lastCookie
+ }
+ </call>
+ <script>
+ searchRC = STAXResult[0][0]
+ searchResult = STAXResult[0][1]
+ </script>
+ <if expr="searchRC == 0">
+ <sequence>
+ <message>
+ 'This is the ECL entry as read from server %s:%s: \n%s'\
+ % (replServer.getHostname(), replServer.getPort(),
+ searchResult)
+ </message>
+ <call function="'parseLdifEntry'">
+ { 'ldifEntry' : searchResult }
+ </call>
+ <script>
+ eclEntry = STAXResult
+
+ nextCookie = eclEntry['changelogcookie'][0]
+ </script>
+ <message>
+ 'Parsed changelog entry: \n%s' % eclEntry
+ </message>
+ <message>
+ 'Cookie to use for the next ECL search: %s' % \
+ nextCookie
+ </message>
+ </sequence>
+ <else>
+ <message log="1" level="'Error'">
+ 'Could not read changelog on replication server %s:%s' \
+ % (replServer.getHostname(), replServer.getPort())
+ </message>
+ </else>
+ </if>
+
+ <if expr="modEntry and eclEntry">
+ <call function="'checkChangelogEntry'">
+ { 'location' : masterHost,
+ 'dsPath' : masterPath,
+ 'changelogEntry' : eclEntry,
+ 'targetDN' : myTargetDN,
+ 'changeType' : myChangeType,
+ 'changeTime' : myChangeTime,
+ 'targetEntryUUID' : myTargetEntryUUID,
+ 'changes' : myChanges
+ }
+ </call>
+ <else>
+ <sequence>
+ <message log="1" level="'Error'">
+ 'Unable to check external changelog entry (failed to \
+ read entries %s and/or %s)' % \
+ (myEntry.getDn(), eclEntry['dn'][0])
+ </message>
+ <call function="'testFailed'"/>
+ </sequence>
+ </else>
+ </if>
+
+ </sequence>
+ </iterate>
+
+ <script>
+ # set the lastCookie for the next ECL search
+ if nextCookie:
+ lastCookie = nextCookie
+
+ # reset variables, just in case
+ modEntry = None
+ eclEntry = None
+ </script>
+
+ <call function="'testCase_Postamble'"/>
+ </sequence>
+ </testcase>
+
+
+ <import machine="STAF_LOCAL_HOSTNAME"
+ file="'%s/testcases/replication/replication_cleanup.xml'
+ % (TESTS_DIR)"/>
+ <call function="'replication_cleanup'" />
+
+ <call function="'testSuite_Postamble'"/>
+ </sequence>
+ </block>
+ </sequence>
+ </function>
+</stax>
diff --git a/opendj-sdk/opends/tests/staf-tests/functional-tests/testcases/replication/replication.xml b/opendj-sdk/opends/tests/staf-tests/functional-tests/testcases/replication/replication.xml
index b64bac3..1e75ac9 100644
--- a/opendj-sdk/opends/tests/staf-tests/functional-tests/testcases/replication/replication.xml
+++ b/opendj-sdk/opends/tests/staf-tests/functional-tests/testcases/replication/replication.xml
@@ -58,6 +58,7 @@
testList.append('encryption')
testList.append('changelog')
testList.append('conflict')
+ testList.append('externalchangelog')
globalAssuredReplication = None
diff --git a/opendj-sdk/opends/tests/staf-tests/shared/functions/ldap.xml b/opendj-sdk/opends/tests/staf-tests/shared/functions/ldap.xml
index 4c803e5..f7081b6 100755
--- a/opendj-sdk/opends/tests/staf-tests/shared/functions/ldap.xml
+++ b/opendj-sdk/opends/tests/staf-tests/shared/functions/ldap.xml
@@ -3083,6 +3083,151 @@
</sequence>
</function>
+
+ <!-- Rename an entry -->
+ <function name="modifyDn">
+ <function-prolog>
+ This function renames an entry, either by a modRDN or by a modDN
+ </function-prolog>
+ <function-map-args>
+ <function-arg-def name="location"
+ type="optional"
+ default="STAF_REMOTE_HOSTNAME">
+ <function-arg-description>
+ Location of target host
+ </function-arg-description>
+ <function-arg-property name="type" value="hostname"/>
+ </function-arg-def>
+ <function-arg-def name="dsPath"
+ type="optional"
+ default="'%s/%s' % (DIRECTORY_INSTANCE_DIR,OPENDSNAME)">
+ <function-arg-description>
+ Pathname to installation root
+ </function-arg-description>
+ <function-arg-property name="type" value="filepath"/>
+ </function-arg-def>
+ <function-arg-def name="dsInstanceHost"
+ type="optional"
+ default="STAF_REMOTE_HOSTNAME">
+ <function-arg-description>
+ Directory server hostname or IP address
+ </function-arg-description>
+ <function-arg-property name="type" value="hostname"/>
+ </function-arg-def>
+ <function-arg-def name="dsInstancePort" type="required">
+ <function-arg-description>
+ Directory server port number
+ </function-arg-description>
+ <function-arg-property name="type" value="Port number"/>
+ </function-arg-def>
+ <function-arg-def name="dsInstanceDn" type="required">
+ <function-arg-description>
+ Bind DN
+ </function-arg-description>
+ <function-arg-property name="type" value="DN"/>
+ </function-arg-def>
+ <function-arg-def name="dsInstancePswd" type="required">
+ <function-arg-description>
+ Bind password
+ </function-arg-description>
+ <function-arg-property name="type" value="string"/>
+ </function-arg-def>
+ <function-arg-def name="DNToModify" type="required">
+ <function-arg-description>
+ DN to modify
+ </function-arg-description>
+ <function-arg-property name="type" value="DN"/>
+ </function-arg-def>
+ <function-arg-def name="newRDN"
+ type="optional"
+ default="None">
+ <function-arg-description>
+ New rdn name : ie uid=jdoe_bis. If not passed, the newRDN will be the
+ same old rdn
+ </function-arg-description>
+ <function-arg-property name="type" value="string"/>
+ </function-arg-def>
+ <function-arg-def name="deleteOldRDN"
+ type="optional"
+ default="None">
+ <function-arg-description>
+ 1 : delete old rdn, 0 do not delete old rdn, default value is 1
+ </function-arg-description>
+ <function-arg-property name="type" value="integer"/>
+ </function-arg-def>
+ <function-arg-def name="newSuperior"
+ type="optional"
+ default="None">
+ <function-arg-description>
+ New parent entry for the entry
+ </function-arg-description>
+ <function-arg-property name="type" value="DN"/>
+ </function-arg-def>
+ <function-arg-def name="expectedRC" type="optional" default="0">
+ <function-arg-description>
+ Expected return code value. Default value is 0
+ Wildcard 'noCheck' to not check the RC
+ </function-arg-description>
+ <function-arg-property name="type" value="integer"/>
+ </function-arg-def>
+ <function-arg-def name="knownIssue" type="optional" default="None">
+ <function-arg-description>
+ Known issue. Corresponds to an issue number.
+ </function-arg-description>
+ <function-arg-property name="type" value="string" />
+ </function-arg-def>
+ </function-map-args>
+ <sequence>
+
+ <!-- Local variables -->
+ <script>
+ mylocation=location
+ #Build the Command
+ STAFCmdParamsList=[]
+ STAFCmdParams=''
+ STAFCmd=''
+ </script>
+
+ <!-- Set common ldap arguments -->
+ <call function="'_ldapCommonArgs'" />
+ <script>
+ if DNToModify:
+ STAFCmdParamsList.append('-d "%s"' % DNToModify)
+
+ if newRDN:
+ STAFCmdParamsList.append('-e "%s"' % newRDN)
+
+ if deleteOldRDN == 0:
+ STAFCmdParamsList.append('-f "false"')
+ elif deleteOldRDN == 1:
+ STAFCmdParamsList.append('-f "true"')
+
+ if newSuperior:
+ STAFCmdParamsList.append('-g "%s"' % newSuperior)
+
+ STAFCmdParams=' '.join(STAFCmdParamsList)
+
+ STAFCmd='modifyDn'
+ </script>
+ <call function="'runCommand'" >
+ { 'name' : 'Modify DN',
+ 'command' : '%s/bin/java' % JAVA_HOME,
+ 'arguments' : '%s %s' % (STAFCmd,STAFCmdParams),
+ 'location' : location,
+ 'envCmd' : ['CLASSPATH=%s/../%s/ldapjndi' % (dsPath,remote.reljavadir)],
+ 'path' : '%s/../%s/ldapjndi' % (dsPath,remote.reljavadir),
+ 'expectedRC': expectedRC,
+ 'knownIssue': knownIssue
+ }
+ </call>
+ <return>
+ STAXResult
+ </return>
+ </sequence>
+ </function>
+
+
+
<!-- Modify an attribute -->
<function name="saslSearch">
<function-prolog>
@@ -3298,5 +3443,183 @@
</sequence>
</function>
+
+
+
+ <function name="SearchExternalChangelog">
+ <function-prolog>
+ This function searches the external changelog
+ </function-prolog>
+ <function-map-args>
+ <function-arg-def name="location" type="optional" default="STAF_REMOTE_HOSTNAME">
+ <function-arg-description>
+ Location of target host
+ </function-arg-description>
+ <function-arg-property name="type" value="hostname"/>
+ </function-arg-def>
+ <function-arg-def name="dsPath" type="optional" default="'%s/%s' % (DIRECTORY_INSTANCE_BIN,OPENDSNAME)">
+ <function-arg-description>
+ Pathname to installation root
+ </function-arg-description>
+ <function-arg-property name="type" value="pathname"/>
+ </function-arg-def>
+ <function-arg-def name="dsInstanceHost" type="optional">
+ <function-arg-description>
+ Directory Server Host Name
+ </function-arg-description>
+ <function-arg-property name="type" value="hostname"/>
+ </function-arg-def>
+ <function-arg-def name="dsInstancePort" type="optional">
+ <function-arg-description>
+ Directory Server Port Number
+ </function-arg-description>
+ <function-arg-property name="type" value="integer"/>
+ </function-arg-def>
+ <function-arg-def name="dsInstanceDn" type="optional">
+ <function-arg-description>
+ Directory Server Manager DN
+ </function-arg-description>
+ <function-arg-property name="type" value="dn"/>
+ </function-arg-def>
+ <function-arg-def name="dsInstancePswd" type="optional">
+ <function-arg-description>
+ Directory Server Manager Password
+ </function-arg-description>
+ <function-arg-property name="type" value="string"/>
+ </function-arg-def>
+ <function-arg-def name="dsScope" type="optional">
+ <function-arg-description>
+ The scope of the search operation
+ </function-arg-description>
+ <function-arg-property name="type" value="dn"/>
+ </function-arg-def>
+ <function-arg-def name="dsBaseDN" type="optional">
+ <function-arg-description>
+ The baseDN for the search operation
+ </function-arg-description>
+ <function-arg-property name="type" value="dn"/>
+ </function-arg-def>
+ <function-arg-def name="dsFilter" type="required">
+ <function-arg-description>
+ The filter for the search operation
+ </function-arg-description>
+ <function-arg-property name="type" value="filter"/>
+ </function-arg-def>
+ <function-arg-def name="extraParams" type="optional">
+ <function-arg-description>
+ Optional extra parameters for specific test cases
+ </function-arg-description>
+ <function-arg-property name="type" value="string"/>
+ </function-arg-def>
+ <function-arg-def name="attributes" type="optional">
+ <function-arg-description>
+ Optional Attributes to return
+ </function-arg-description>
+ <function-arg-property name="type" value="attributes"/>
+ </function-arg-def>
+ <function-arg-def name="changelogCookie"
+ type="optional"
+ default="None">
+ <function-arg-description>
+ Changelog cookie of the last change retrieved.
+ (OpenDS external changelog => non draft-compatible mode)
+ </function-arg-description>
+ <function-arg-property name="type" value="string"/>
+ </function-arg-def>
+ <function-arg-def name="changeNumberFilter"
+ type="optional"
+ default="None">
+ <function-arg-description>
+ Changenumber corresponding to the last change retrieved.
+ (Changelog draft-compatible mode)
+ </function-arg-description>
+ <function-arg-property name="type" value="filter"/>
+ </function-arg-def>
+ <function-arg-def name="expectedRC" type="optional" default="0">
+ <function-arg-description>
+ Expected return code value. Default value is 0.
+ Wildcard 'noCheck' to not check the RC
+ </function-arg-description>
+ <function-arg-property name="type" value="integer"/>
+ </function-arg-def>
+ <function-arg-def name="knownIssue" type="optional" default="None">
+ <function-arg-description>
+ Known issue. Corresponds to an issue number.
+ </function-arg-description>
+ <function-arg-property name="type" value="string" />
+ </function-arg-def>
+ </function-map-args>
+ <sequence>
+
+ <!-- Local variables -->
+ <script>
+ mylocation=location
+ </script>
+
+ <!-- Build the Command -->
+ <script>
+ STAFCmdParamsList=[]
+ STAFCmdParams=''
+
+ if dsPath:
+ dsBinPath='%s/%s' % (dsPath,fileFolder)
+ STAFCmd='%s/ldapsearch%s' % (dsBinPath,fileExt)
+
+ </script>
+
+ <!-- Set common ldap arguments -->
+ <call function="'_ldapCommonArgs'"/>
+
+ <script>
+ if changelogCookie:
+ control = '1.3.6.1.4.1.26027.1.5.4:false:%s' % changelogCookie
+ STAFCmdParamsList.append('--control "%s"' % control)
+
+ if dsScope:
+ STAFCmdParamsList.append('-s %s' % dsScope)
+
+ if extraParams:
+ STAFCmdParamsList.append('%s' % extraParams)
+
+ if dsBaseDN:
+ STAFCmdParamsList.append('-b "%s"' % dsBaseDN)
+
+ if dsFilter:
+ if changeNumberFilter:
+ searchFilter = '&%s%s' % (changeNumberFilter, dsFilter)
+ else:
+ searchFilter = dsFilter
+ STAFCmdParamsList.append('"%s"' % searchFilter)
+ else:
+ if changeNumberFilter:
+ STAFCmdParamsList.append('"%s"' % changeNumberFilter)
+
+ if attributes:
+ STAFCmdParamsList.append('%s' % attributes)
+ else:
+ STAFCmdParamsList.append('@changeLogEntry')
+
+ STAFCmdParams=' '.join(STAFCmdParamsList)
+ </script>
+
+ <message>
+ '%s %s' % (STAFCmd, STAFCmdParams)
+ </message>
+
+ <call function="'runCommand'">
+ { 'command' : STAFCmd,
+ 'arguments' : STAFCmdParams,
+ 'location' : location,
+ 'name' : 'ldapsearch',
+ 'expectedRC': expectedRC,
+ 'knownIssue': knownIssue
+ }
+ </call>
+ <return>
+ STAXResult
+ </return>
+ </sequence>
+
+ </function>
</stax>
diff --git a/opendj-sdk/opends/tests/staf-tests/shared/functions/utils.xml b/opendj-sdk/opends/tests/staf-tests/shared/functions/utils.xml
index 3a211e6..68a2e67 100755
--- a/opendj-sdk/opends/tests/staf-tests/shared/functions/utils.xml
+++ b/opendj-sdk/opends/tests/staf-tests/shared/functions/utils.xml
@@ -242,6 +242,15 @@
</function-arg-description>
<function-arg-property name="type" value="string"/>
</function-arg-def>
+ <function-arg-def name="searchType"
+ type="optional"
+ default="'substring'">
+ <function-arg-description>
+ the type of the search: substring, exact-case-insensitive or
+ exact-case-sensitive
+ </function-arg-description>
+ <function-arg-property name="type" value="string"/>
+ </function-arg-def>
<function-arg-def name="knownIssue" type="optional" default="None">
<function-arg-description>
Known issue. Corresponds to an issue number.
@@ -279,13 +288,22 @@
<return>[myRC, myReason]</return>
</sequence>
</if>
+
+ <script>
+ if searchType == 'substring':
+ searchResult = (re.search(searchre, returnString) != None)
+ elif searchType == 'exact-case-sensitive':
+ searchResult = (expectedString == returnString)
+ elif searchType == 'exact-case-insensitive':
+ searchResult = (expectedString.lower() == returnString.lower())
+ </script>
<!-- Search for the expectedString -->
- <if expr='re.search(searchre, returnString) != None'>
+ <if expr='searchResult'>
<sequence>
<message log="1">
- 'Found substring, %s, in the return string' \
- % (expectedString)
+ 'Search type: %s Found substring, %s, in the return string' \
+ % (searchType, expectedString)
</message>
<script>
myRC = 0
@@ -295,8 +313,8 @@
<else>
<sequence>
<message log="1">
- 'Did not find substring, %s, in the return string, %s' \
- % (expectedString, returnString)
+ 'Search type: %s Did not find substring, %s, in the return \
+ string, %s' % (searchType, expectedString, returnString)
</message>
<script>
myRC = 1
@@ -2938,5 +2956,635 @@
</sequence>
</function>
+
+
+ <!-- This function parses an ldif entry -->
+ <function name="parseLdifEntry">
+ <function-prolog>
+ This function parses an ldif entry and returns a dictionary, e.g.:
+ {'dn':['o=example'],'objectclass':['top','organization'],'o':['example']}
+ </function-prolog>
+ <function-map-args>
+ <function-arg-def name="ldifEntry" type="required">
+ <function-arg-description>
+ Ldif entry to parse (single string).
+ </function-arg-description>
+ <function-arg-property name="type" value="string"/>
+ </function-arg-def>
+ </function-map-args>
+ <sequence>
+ <script>
+ parsedEntry = {}
+ prevAttr = None
+ prevVal = None
+
+ for line in ldifEntry.splitlines():
+ notBlank = (len(line.strip()) != 0)
+ if notBlank and (not line.startswith(' ')):
+ # line corresponds to an attr:val
+ attr = line[:line.find(':')].strip().lower()
+ val = line[line.find(':') + 1:].lstrip()
+ if val.startswith(':'):
+ val = val[1:].lstrip()
+ if attr == 'objectclass':
+ val = val.lower()
+
+ if not (attr in parsedEntry.keys()):
+ # This is the first occurrence of this attr
+ parsedEntry[attr] = [val]
+ else:
+ # There is already some value for this attr
+ parsedEntry[attr].append(val)
+
+ prevAttr = attr
+ prevVal = val
+ elif notBlank:
+ # line corresponds to a trailing value
+ parsedEntry[prevAttr].remove(prevVal)
+ val = prevVal + line.lstrip()
+ parsedEntry[prevAttr].append(val)
+ prevVal = val
+ </script>
+
+ <return> parsedEntry </return>
+ </sequence>
+ </function>
+
+
+
+ <!-- This function parses an ldif change -->
+ <function name="parseLdifChange">
+ <function-prolog>
+ This function parses an ldif change and returns a list, e.g.:
+ [ ['replace','l','London'], ['add','description','This is a test'] ]
+ </function-prolog>
+
+ <function-map-args>
+ <function-arg-def name="ldifChange" type="required">
+ <function-arg-description>
+ Ldif change to parse (single string).
+ </function-arg-description>
+ <function-arg-property name="type" value="string"/>
+ </function-arg-def>
+ </function-map-args>
+ <sequence>
+ <script>
+ parsedChange = []
+ mod = []
+ prevAttr = None
+ prevVal = None
+
+ for line in ldifChange.splitlines():
+ notBlank = (len(line.strip()) != 0)
+ if notBlank and (not line.startswith(' ')) and (not line.startswith('-')):
+ # line corresponds to an attr:val
+ attr = line[:line.find(':')].strip().lower()
+ val = line[line.find(':') + 1:].lstrip()
+
+ if val.startswith(':'):
+ val = val[1:].lstrip()
+
+ if attr == 'objectclass':
+ val = val.lower()
+
+ if (prevVal != None) and (attr == prevVal.lower()):
+ # attr represents indeed an attribute type, so we may assume the
+ # mod already has [mod_type,attr_type]
+ mod.append(val)
+ else:
+ # attr represents the mod_type, and val the attr_type
+ mod.append(attr)
+ mod.append(val.lower())
+
+ prevAttr = attr
+ prevVal = val
+ elif notBlank and line.startswith(' '):
+ # line corresponds to a trailing value
+ mod.remove(prevVal)
+ val = prevVal + line.lstrip()
+ mod.append(val)
+ prevVal = val
+ else:
+ # line is empty or line starts with '-'; this means that
+ # the mod is complete, so we can add it to the parsedChange list
+ parsedChange.append(mod)
+ mod = []
+
+ if len(mod) != 0:
+ # add the trailing mod to the parsedChange list
+ parsedChange.append(mod)
+ </script>
+
+ <return> parsedChange </return>
+ </sequence>
+ </function>
+
+ <!-- This function checks the content of an external changelog entry -->
+ <function name="checkChangelogEntry">
+ <function-prolog>
+ This function checks the content of an external changelog entry
+ </function-prolog>
+
+ <function-map-args>
+ <function-arg-def name="location"
+ type="optional"
+ default="STAF_REMOTE_HOSTNAME">
+ <function-arg-description>
+ Location of target host
+ </function-arg-description>
+ <function-arg-property name="type" value="hostname"/>
+ </function-arg-def>
+ <function-arg-def name="dsPath"
+ type="optional"
+ default="'%s/%s' % (DIRECTORY_INSTANCE_BIN,OPENDSNAME)">
+ <function-arg-description>
+ Pathname to installation root
+ </function-arg-description>
+ <function-arg-property name="type" value="filepath"/>
+ </function-arg-def>
+ <function-arg-def name="changelogEntry" type="required">
+ <function-arg-description>
+ External changelog entry (as an output of parseLdifEntry)
+ </function-arg-description>
+ <function-arg-property name="type" value="dictionary"/>
+ </function-arg-def>
+ <function-arg-def name="targetDN" type="required">
+ <function-arg-description>
+ DN of the target entry for the change
+ </function-arg-description>
+ <function-arg-property name="type" value="string"/>
+ </function-arg-def>
+ <function-arg-def name="changeType" type="required">
+ <function-arg-description>
+ Change type (e.g. add, delete, modify)
+ </function-arg-description>
+ <function-arg-property name="type" value="string"/>
+ </function-arg-def>
+ <function-arg-def name="changeTime"
+ type="optional"
+ default="None">
+ <function-arg-description>
+ Change time
+ </function-arg-description>
+ <function-arg-property name="type" value="string"/>
+ </function-arg-def>
+ <function-arg-def name="changeNumber"
+ type="optional"
+ default="None">
+ <function-arg-description>
+ Changenumber (only for changelog draft-compatible mode)
+ </function-arg-description>
+ <function-arg-property name="type" value="string"/>
+ </function-arg-def>
+ <function-arg-def name="replicationCSN"
+ type="optional"
+ default="None">
+ <function-arg-description>
+ Replication CSN
+ </function-arg-description>
+ <function-arg-property name="type" value="string"/>
+ </function-arg-def>
+ <function-arg-def name="targetEntryUUID"
+ type="optional"
+ default="None">
+ <function-arg-description>
+ Target entry uuid
+ </function-arg-description>
+ <function-arg-property name="type" value="string"/>
+ </function-arg-def>
+ <function-arg-def name="replicaIdentifier"
+ type="optional"
+ default="None">
+ <function-arg-description>
+ Replica Identifier
+ </function-arg-description>
+ <function-arg-property name="type" value="string"/>
+ </function-arg-def>
+ <function-arg-def name="newRDN"
+ type="optional"
+ default="None">
+ <function-arg-description>
+ NewRDN
+ </function-arg-description>
+ <function-arg-property name="type" value="string"/>
+ </function-arg-def>
+ <function-arg-def name="deleteOldRDN"
+ type="optional"
+ default="None">
+ <function-arg-description>
+ DeleteOldRDN
+ </function-arg-description>
+ <function-arg-property name="type" value="string"/>
+ </function-arg-def>
+ <function-arg-def name="newSuperior"
+ type="optional"
+ default="None">
+ <function-arg-description>
+ NewSuperior
+ </function-arg-description>
+ <function-arg-property name="type" value="string"/>
+ </function-arg-def>
+ <function-arg-def name="changes"
+ type="optional"
+ default="None">
+ <function-arg-description>
+ Changes. If changetype == add, changes should be a map, e.g.:
+ {'dn':['o=example'],'objectclass':['top','organization'],'o':['example']}
+ If changetype == modify, changes should be a list, e.g.:
+ [ ['replace','l','London'], ['add','description','This is a test'] ]
+ </function-arg-description>
+ <function-arg-property name="type" value="string"/>
+ </function-arg-def>
+ <function-arg-def name="knownIssue" type="optional" default="None">
+ <function-arg-description>
+ Known issue. Corresponds to an issue number.
+ </function-arg-description>
+ <function-arg-property name="type" value="string" />
+ </function-arg-def>
+ </function-map-args>
+
+ <sequence>
+ <script>
+ myLocation = location
+ myPath = dsPath
+
+ # Mandatory attributes in a changeLogEntry
+ ecl_DN = changelogEntry['dn'][0]
+ ecl_targetDN = changelogEntry['targetdn'][0]
+ ecl_changeType = changelogEntry['changetype'][0]
+ ecl_changeTime = changelogEntry['changetime'][0]
+ ecl_changeNumber = changelogEntry['changenumber'][0]
+
+ # Optional attributes
+ ecl_replicationCSN = None
+ ecl_replicaIdentifier = None
+ ecl_targetEntryUUID = None
+ ecl_newRDN = None
+ ecl_deleteOldRDN = None
+ ecl_newSuperior = None
+ ecl_changes = None
+
+ if 'replicationcsn' in changelogEntry.keys():
+ ecl_replicationCSN = changelogEntry['replicationcsn'][0]
+ if 'replicaidentifier' in changelogEntry.keys():
+ ecl_replicaIdentifier = changelogEntry['replicaidentifier'][0]
+ if 'targetentryuuid' in changelogEntry.keys():
+ ecl_targetEntryUUID = changelogEntry['targetentryuuid'][0]
+ if 'newrdn' in changelogEntry.keys():
+ ecl_newRDN = changelogEntry['newrdn'][0]
+ if 'deleteoldrdn' in changelogEntry.keys():
+ ecl_deleteOldRDN = changelogEntry['deleteoldrdn'][0]
+ if 'newsuperior' in changelogEntry.keys():
+ ecl_newSuperior = changelogEntry['newsuperior'][0]
+ if 'changes' in changelogEntry.keys():
+ ecl_changes = changelogEntry['changes'][0]
+ </script>
+
+ <message>
+ 'checkChangelogEntry: Checking changelog entry %s against expected \
+ values' % ecl_DN
+ </message>
+
+ <message>
+ 'checkChangelogEntry: Checking targetDN'
+ </message>
+ <call function="'searchString'">
+ { 'returnString' : ecl_targetDN,
+ 'expectedString' : targetDN,
+ 'searchType' : 'exact-case-insensitive'
+ }
+ </call>
+
+ <message>
+ 'checkChangelogEntry: Checking changeType'
+ </message>
+ <call function="'searchString'">
+ { 'returnString' : ecl_changeType,
+ 'expectedString' : changeType,
+ 'searchType' : 'exact-case-insensitive'
+ }
+ </call>
+
+ <if expr="changeTime">
+ <sequence>
+ <message>
+ 'checkChangelogEntry: Checking changeTime'
+ </message>
+ <call function="'searchString'">
+ { 'returnString' : ecl_changeTime,
+ 'expectedString' : changeTime,
+ 'searchType' : 'exact-case-insensitive'
+ }
+ </call>
+ </sequence>
+ </if>
+
+ <if expr="changeNumber">
+ <sequence>
+ <message>
+ 'checkChangelogEntry: Checking changeNumber'
+ </message>
+ <call function="'searchString'">
+ { 'returnString' : ecl_changeNumber,
+ 'expectedString' : changeNumber,
+ 'searchType' : 'exact-case-sensitive'
+ }
+ </call>
+ </sequence>
+ </if>
+
+ <if expr="replicationCSN">
+ <if expr="ecl_replicationCSN">
+ <sequence>
+ <message>
+ 'checkChangelogEntry: Checking replicationCSN'
+ </message>
+ <call function="'searchString'">
+ { 'returnString' : ecl_replicationCSN,
+ 'expectedString' : replicationCSN,
+ 'searchType' : 'exact-case-insensitive'
+ }
+ </call>
+ </sequence>
+ <else>
+ <sequence>
+ <message log="1" level="'Error'">
+ 'No replicationCSN could be found in the changelog entry'
+ </message>
+ <call function="'testFailed'"/>
+ </sequence>
+ </else>
+ </if>
+ </if>
+
+ <if expr="replicaIdentifier">
+ <if expr="ecl_replicaIdentifier">
+ <sequence>
+ <message>
+ 'checkChangelogEntry: Checking replicaIdentifier'
+ </message>
+ <call function="'searchString'">
+ { 'returnString' : ecl_replicaIdentifier,
+ 'expectedString' : replicaIdentifier,
+ 'searchType' : 'exact-case-sensitive'
+ }
+ </call>
+ </sequence>
+ <else>
+ <sequence>
+ <message log="1" level="'Error'">
+ 'No replicaIdentifier could be found in the changelog entry'
+ </message>
+ <call function="'testFailed'"/>
+ </sequence>
+ </else>
+ </if>
+ </if>
+
+ <if expr="targetEntryUUID">
+ <if expr="ecl_targetEntryUUID">
+ <sequence>
+ <message>
+ 'checkChangelogEntry: Checking targetEntryUUID'
+ </message>
+ <call function="'searchString'">
+ { 'returnString' : ecl_targetEntryUUID,
+ 'expectedString' : targetEntryUUID,
+ 'searchType' : 'exact-case-insensitive'
+ }
+ </call>
+ </sequence>
+ <else>
+ <sequence>
+ <message log="1" level="'Error'">
+ 'No targetEntryUUID could be found in the changelog entry'
+ </message>
+ <call function="'testFailed'"/>
+ </sequence>
+ </else>
+ </if>
+ </if>
+
+ <if expr="newRDN">
+ <if expr="ecl_newRDN">
+ <sequence>
+ <message>
+ 'checkChangelogEntry: Checking newRDN'
+ </message>
+ <call function="'searchString'">
+ { 'returnString' : ecl_newRDN,
+ 'expectedString' : newRDN,
+ 'searchType' : 'exact-case-insensitive'
+ }
+ </call>
+ </sequence>
+ <else>
+ <sequence>
+ <message log="1" level="'Error'">
+ 'No newRDN could be found in the changelog entry'
+ </message>
+ <call function="'testFailed'"/>
+ </sequence>
+ </else>
+ </if>
+ </if>
+
+ <if expr="deleteOldRDN">
+ <if expr="ecl_deleteOldRDN">
+ <sequence>
+ <message>
+ 'checkChangelogEntry: Checking deleteOldRDN'
+ </message>
+ <call function="'searchString'">
+ { 'returnString' : ecl_deleteOldRDN,
+ 'expectedString' : deleteOldRDN,
+ 'searchType' : 'exact-case-sensitive'
+ }
+ </call>
+ </sequence>
+ <else>
+ <sequence>
+ <message log="1" level="'Error'">
+ 'No deleteOldRDN could be found in the changelog entry'
+ </message>
+ <call function="'testFailed'"/>
+ </sequence>
+ </else>
+ </if>
+ </if>
+
+ <if expr="newSuperior">
+ <if expr="ecl_newSuperior">
+ <sequence>
+ <message>
+ 'checkChangelogEntry: Checking newSuperior'
+ </message>
+ <call function="'searchString'">
+ { 'returnString' : ecl_newSuperior,
+ 'expectedString' : newSuperior,
+ 'searchType' : 'exact-case-insensitive'
+ }
+ </call>
+ </sequence>
+ <else>
+ <sequence>
+ <message log="1" level="'Error'">
+ 'No newSuperior could be found in the changelog entry'
+ </message>
+ <call function="'testFailed'"/>
+ </sequence>
+ </else>
+ </if>
+ </if>
+
+ <if expr="changes">
+ <if expr="ecl_changes">
+ <sequence>
+ <!-- Decode the changes that are encoded in base64 -->
+ <message>
+ 'checkChangelogEntry: Decode external changelog entry changes'
+ </message>
+ <call function="'Base64WithScript'">
+ { 'location' : myLocation,
+ 'dsPath' : myPath,
+ 'subcommand' : 'decode',
+ 'encodedData' : ecl_changes
+ }
+ </call>
+ <!-- STAXResult is not always a list-->
+ <script>
+ try:
+ decodeRC, decodedChanges = STAXResult[0]
+ except AttributeError, details:
+ decodedChanges = 'AttributeError: can not parse STAXResult %s' \
+ % details
+ decodeRC = '1'
+ </script>
+ <message>
+ 'checkChangelogEntry: Decoded changes:\n%s' % decodedChanges
+ </message>
+
+ <message>
+ 'checkChangelogEntry: Checking changes'
+ </message>
+ <if expr="decodeRC == 0 and changeType == 'add'">
+ <!-- If changetype:add, the changes look like a sequence of
+ ! attribute:value, so we may parse them as an ldif entry -->
+ <sequence>
+ <call function="'parseLdifEntry'">
+ { 'ldifEntry' : decodedChanges }
+ </call>
+ <script>
+ ecl_changesMap = STAXResult
+ </script>
+ <message>
+ 'Parsed changelog entry changes: \n%s' % ecl_changesMap
+ </message>
+ <iterate var="attr" in="changes.keys()">
+ <sequence>
+ <script>
+ valueList = changes[attr]
+ ecl_valueList = None
+
+ if attr in ecl_changesMap.keys():
+ ecl_valueList = ecl_changesMap[attr]
+ ecl_valueList.sort()
+ valueList.sort()
+ </script>
+ <if expr="ecl_valueList != None">
+ <sequence>
+ <message>
+ 'checkChangelogEntry: Checking changes: %s' % attr
+ </message>
+ <if expr="valueList == ecl_valueList">
+ <message>
+ 'Found expected values in changes: %s' % valueList
+ </message>
+ <else>
+ <sequence>
+ <message log="1" level="'Error'">
+ 'Expected values %s could not be found in %s' \
+ % (valueList, ecl_valueList)
+ </message>
+ <call function="'testFailed'"/>
+ </sequence>
+ </else>
+ </if>
+ </sequence>
+ <else>
+ <sequence>
+ <message log="1" level="'Error'">
+ 'No %s could be found in the changes' % attr
+ </message>
+ <call function="'testFailed'"/>
+ </sequence>
+ </else>
+ </if>
+ </sequence>
+ </iterate>
+ </sequence>
+
+ <elseif expr="decodeRC == 0">
+ <!-- If changetype:modify, the changes look like a sequence of
+ ! mod_type:attribute
+ ! attribute:value
+ ! so we need to treat them differently -->
+ <sequence>
+ <call function="'parseLdifChange'">
+ { 'ldifChange' : decodedChanges }
+ </call>
+ <script>
+ ecl_changesList = STAXResult
+ </script>
+ <message>
+ 'Parsed changelog entry changes: \n%s' % ecl_changesList
+ </message>
+ <iterate var="mod" in="changes">
+ <sequence>
+ <script>
+ mod_type = mod[0]
+ mod_attr = mod[1]
+ mod_val = None
+ if len(mod) == 3:
+ mod_val = mod[2]
+ </script>
+ <message>
+ 'checkChangelogEntry: Checking changes: %s' % mod
+ </message>
+ <if expr="mod in ecl_changesList">
+ <message>
+ 'Found expected change:\n %s: %s\n %s: %s\n' \
+ % (mod_type, mod_attr, mod_attr, mod_val)
+ </message>
+ <else>
+ <sequence>
+ <message log="1" level="'Error'">
+ 'Expected change %s could not be found in %s'\
+ % (mod, ecl_changesList)
+ </message>
+ <call function="'testFailed'"/>
+ </sequence>
+ </else>
+ </if>
+ </sequence>
+ </iterate>
+ </sequence>
+ </elseif>
+ </if>
+
+ </sequence>
+ <else>
+ <sequence>
+ <message log="1" level="'Error'">
+ 'No changes could be found in the changelog entry'
+ </message>
+ <call function="'testFailed'"/>
+ </sequence>
+ </else>
+ </if>
+ </if>
+
+ </sequence>
+ </function>
</stax>
diff --git a/opendj-sdk/opends/tests/staf-tests/shared/java/ldapjndi/modifyDn.java b/opendj-sdk/opends/tests/staf-tests/shared/java/ldapjndi/modifyDn.java
new file mode 100644
index 0000000..3078615
--- /dev/null
+++ b/opendj-sdk/opends/tests/staf-tests/shared/java/ldapjndi/modifyDn.java
@@ -0,0 +1,169 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2009 Sun Microsystems, Inc.
+ */
+
+import java.util.Hashtable;
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.ldap.LdapContext;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.InitialLdapContext;
+import javax.naming.CommunicationException;
+import java.util.HashSet;
+import java.util.Iterator;
+
+/**
+ * Modify the DN of an entry.
+ * The operation can be a modDN (tree move) or a modRDN.
+ * The function returns the ldap error code
+ */
+public class modifyDn {
+
+ /**
+ * Main.
+ *
+ * @param args arguments
+ */
+ public static void main(String[] args) {
+
+ String hostname=null;
+ String ldapPort=null;
+ String principal=null;
+ String credential=null;
+ String dnToModify=null;
+ String newRDN=null;
+ String deleteOldRDN=null;
+ String newSuperior=null;
+ String errorCode=null;
+ String errorMessage=null;
+
+ Hashtable envLdap = new Hashtable();
+ LdapContext ctx;
+ LdapName nameToModify;
+ LdapName targetName;
+ String targetDn;
+
+
+ for (int k=0; k< args.length; k++) {
+ String opt1 = args[k];
+ String val1 = args[k+1];
+
+ if (opt1.equals("-h")) {
+ hostname = val1;
+ }
+ if (opt1.equals("-p")) {
+ ldapPort = val1;
+ }
+ if (opt1.equals("-D")) {
+ principal = val1;
+ }
+ if (opt1.equals("-w")) {
+ credential = val1;
+ }
+ if (opt1.equals("-d")) {
+ dnToModify = val1;
+ }
+ if (opt1.equals("-e")) {
+ newRDN = val1;
+ }
+ if (opt1.equals("-f")) {
+ deleteOldRDN = val1;
+ }
+ if (opt1.equals("-g")) {
+ newSuperior = val1;
+ }
+ k++;
+ }
+
+
+ String provider = "ldap://" + hostname + ":" + ldapPort + "/";
+
+ envLdap.put("java.naming.factory.initial",
+ "com.sun.jndi.ldap.LdapCtxFactory");
+ envLdap.put(Context.SECURITY_AUTHENTICATION, "simple");
+ envLdap.put(Context.SECURITY_PRINCIPAL, principal);
+ envLdap.put(Context.SECURITY_CREDENTIALS, credential);
+ envLdap.put(Context.PROVIDER_URL, provider);
+
+ // Whether the old RDN attribute values are to be retained
+ // as attributes of the entry, or deleted from the entry.
+ // Default is 'true'
+ if (deleteOldRDN != null) {
+ envLdap.put("java.naming.ldap.deleteRDN", deleteOldRDN);
+ }
+
+ try {
+ System.out.println("Modify the entry " + dnToModify);
+
+ if ( newRDN == null ) {
+ // newRDN = same as old rdn
+ nameToModify = new LdapName(dnToModify);
+ newRDN = (String) nameToModify.remove(nameToModify.size() - 1);
+ }
+
+ if ( newSuperior != null ) {
+ // modDN operation => new parent = newSuperior
+ targetName = new LdapName(newSuperior);
+ } else {
+ // modRDN operation => new parent = old parent
+ targetName = new LdapName(dnToModify);
+ targetName.remove(targetName.size() - 1);
+ }
+ targetName.add(newRDN);
+ targetDn = targetName.toString();
+
+
+ // connect to server
+ ctx = new InitialLdapContext(envLdap, null);
+
+ // rename the entry
+ ctx.rename(dnToModify, targetDn);
+
+ ctx.close();
+ } catch (CommunicationException e1) {
+ errorMessage = e1.getMessage();
+ } catch (NamingException e2) {
+ errorMessage = e2.getMessage();
+ } catch (Exception e3) {
+ errorMessage= e3.getMessage();
+ }
+
+ // No error, the modify is success
+ if ( errorMessage == null ) {
+ errorCode="0";
+ } else {
+ System.out.println(errorMessage);
+ int ind=errorMessage.indexOf("-");
+ if ( ind > 0 ) {
+ errorCode=errorMessage.substring(18, ind-1);
+ } else errorCode="0";
+ }
+
+ int RC = Integer.parseInt(errorCode);
+ System.exit(RC);
+ }
+
+}
--
Gitblit v1.10.0