externalchangelog_common_ecl_tests.xml revision da97433d5cd26e422a370d186f98659383c06721
<?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 2009 Sun Microsystems, Inc.
! -->
<stax>
<defaultcall function="common_ecl_tests"/>
<function name="common_ecl_tests">
<function-prolog>
This function contains the common testcases that can be run on any of the
ECL modes: opends proprietary mode, changelog draft-compatible mode, or
dsee-compatible mode.
</function-prolog>
<function-map-args>
<function-arg-def name="ecl_mode"
type="optional"
default="'opends'">
<function-arg-description>
External Changelog mode: opends, draft, dsee
</function-arg-description>
<function-arg-property name="type" value="string"/>
</function-arg-def>
</function-map-args>
<sequence>
<message>
'Common ECL tests: reset data'
</message>
<!-- Pre-initialise the servers in the topology -->
<call function="'preInitializeReplication'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'dsInstanceHost' : masterHost,
'dsInstanceAdminPort' : master.getAdminPort(),
'localOnly' : False,
'replicationDnList' : [synchroSuffix],
'adminUID' : adminUID,
'adminPswd' : adminPswd
}
</call>
<!-- Stop "master" Directory Server -->
<call function="'StopDsWithScript'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'dsHost' : masterHost,
'dsAdminPort' : master.getAdminPort(),
'dsBindDN' : master.getRootDn(),
'dsBindPwd' : master.getRootPwd()
}
</call>
<!-- Import data into "master" Directory Server -->
<call function="'ImportLdifWithScript'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'dsBackEnd' : DIRECTORY_INSTANCE_BE,
'dsLdifFile' : '%s/replication/Example.ldif' \
% masterDataDir
}
</call>
<!-- Start the Directory Server -->
<call function="'StartDsWithScript'">
{ 'location' : masterHost,
'dsPath' : masterPath
}
</call>
<!-- Wait for DS to start -->
<call function="'isAlive'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'dsInstanceHost' : masterHost,
'dsInstancePort' : master.getPort() ,
'dsInstanceDn' : master.getRootDn() ,
'dsInstancePswd' : master.getRootPwd() ,
'noOfLoops' : 10 ,
'noOfMilliSeconds' : 2000
}
</call>
<!-- Perform the total update -->
<call function="'initializeReplication'">
{ 'location' : clientHost,
'dsPath' : clientPath,
'sourceInstanceHost' : masterHost,
'sourceInstanceAdminPort' : master.getAdminPort(),
'replicationDnList' : ['o=example']
}
</call>
<message>
'Common ECL tests: start test execution in mode: %s' % ecl_mode
</message>
<script>
if ecl_mode == 'opends':
# initialise the searchIndex (lastCookie) value to that for the
# first ECL request
searchIndex = ';'
else :
# initialise the searchIndex (first changenumber) value to that of the
# first change: 1
searchIndex = '1'
nextIndex = None
addOperationalAttrs = """"*" creatorsname createtimestamp entryuuid"""
modOperationalAttrs = """"*" modifiersname modifytimestamp entryuuid"""
class Entry:
def __init__(self, rdn, suffix):
self.userDn = '%s,ou=People,%s' \
% (rdn, suffix)
self.suffix = suffix
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 getSuffix(self):
return self.suffix
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('%s - Add_1' % ecl_mode)">
<sequence>
<call function="'testCase_Preamble'"/>
<message>
'Replication: External Changelog: %s - Add_1. \
Verify add operation is recorded properly in the external \
changelog on each replication server' % ecl_mode
</message>
<!-- Add entry to "master" server -->
<script>
myEntry = Entry('cn=a', synchroSuffix)
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 = RC
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]
if ecl_mode != 'opends':
myChangeNumber = searchIndex
else:
myChangeNumber = None
</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>
<script>
if ecl_mode == 'opends':
lastCookie = searchIndex
chgNumberFilter = None
else:
lastCookie = None
chgNumberFilter = """(changenumber>=%s)""" % searchIndex
</script>
<!-- Search changelog in the various replication servers -->
<iterate var="server"
in="_topologyServerList"
indexvar="indx">
<sequence>
<script>
if globalSplitServers:
replServer = _topologyReplServerList[indx]
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(), searchIndex)
</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=*)',
'changeNumberFilter' : chgNumberFilter,
'changelogCookie' : lastCookie
}
</call>
<script>
searchRC = RC
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
if ecl_mode == 'opends':
nextIndex = eclEntry['changelogcookie'][0]
else:
nextChgNumber = int(eclEntry['changenumber'][0]) + 1
nextIndex = str(nextChgNumber)
</script>
<message>
'Parsed changelog entry: \n%s' % eclEntry
</message>
<message>
'Index to use for the next ECL search: %s' % \
nextIndex
</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,
'changeNumber' : myChangeNumber,
'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 index for the next ECL search
if nextIndex:
searchIndex = nextIndex
nextIndex = None
# 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('%s - Modify_add' % ecl_mode)">
<sequence>
<call function="'testCase_Preamble'"/>
<message>
'Replication: External Changelog: %s - Modify_add. \
Verify modify-add operation is recorded properly in the \
external changelog on each repl server' % ecl_mode
</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 = RC
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])
if ecl_mode != 'opends':
myChangeNumber = searchIndex
else:
myChangeNumber = None
</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>
<script>
if ecl_mode == 'opends':
lastCookie = searchIndex
chgNumberFilter = None
else:
lastCookie = None
chgNumberFilter = """(changenumber>=%s)""" % searchIndex
</script>
<!-- Search changelog in the various replication servers -->
<iterate var="server"
in="_topologyServerList"
indexvar="indx">
<sequence>
<script>
if globalSplitServers:
replServer = _topologyReplServerList[indx]
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(), searchIndex)
</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=*)',
'changeNumberFilter' : chgNumberFilter,
'changelogCookie' : lastCookie
}
</call>
<script>
searchRC = RC
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
if ecl_mode == 'opends':
nextIndex = eclEntry['changelogcookie'][0]
else:
nextChgNumber = int(eclEntry['changenumber'][0]) + 1
nextIndex = str(nextChgNumber)
</script>
<message>
'Parsed changelog entry: \n%s' % eclEntry
</message>
<message>
'Index to use for the next ECL search: %s' % nextIndex
</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,
'changeNumber' : myChangeNumber,
'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 index for the next ECL search
if nextIndex:
searchIndex = nextIndex
nextIndex = None
# 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('%s - Modify_delete' % ecl_mode)">
<sequence>
<call function="'testCase_Preamble'"/>
<message>
'Replication: External Changelog: %s - Modify_delete. \
Verify modify-del operation is recorded properly in the \
external changelog on each repl server' % ecl_mode
</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 = RC
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])
if ecl_mode != 'opends':
myChangeNumber = searchIndex
else:
myChangeNumber = None
</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>
<script>
if ecl_mode == 'opends':
lastCookie = searchIndex
chgNumberFilter = None
else:
lastCookie = None
chgNumberFilter = """(changenumber>=%s)""" % searchIndex
</script>
<!-- Search changelog in the various replication servers -->
<iterate var="server"
in="_topologyServerList"
indexvar="indx">
<sequence>
<script>
if globalSplitServers:
replServer = _topologyReplServerList[indx]
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(), searchIndex)
</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=*)',
'changeNumberFilter' : chgNumberFilter,
'changelogCookie' : lastCookie
}
</call>
<script>
searchRC = RC
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
if ecl_mode == 'opends':
nextIndex = eclEntry['changelogcookie'][0]
else:
nextChgNumber = int(eclEntry['changenumber'][0]) + 1
nextIndex = str(nextChgNumber)
</script>
<message>
'Parsed changelog entry: \n%s' % eclEntry
</message>
<message>
'Index to use for the next ECL search: %s' % nextIndex
</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,
'changeNumber' : myChangeNumber,
'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 index for the next ECL search
if nextIndex:
searchIndex = nextIndex
nextIndex = None
# 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('%s - Modify_replace' % ecl_mode)">
<sequence>
<call function="'testCase_Preamble'"/>
<message>
'Replication: External Changelog: %s - Modify_replace. \
Verify modify-replace operation is recorded properly in the \
external changelog on each repl server' % ecl_mode
</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 = RC
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])
if ecl_mode != 'opends':
myChangeNumber = searchIndex
else:
myChangeNumber = None
</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>
<script>
if ecl_mode == 'opends':
lastCookie = searchIndex
chgNumberFilter = None
else:
lastCookie = None
chgNumberFilter = """(changenumber>=%s)""" % searchIndex
</script>
<!-- Search changelog in the various replication servers -->
<iterate var="server"
in="_topologyServerList"
indexvar="indx">
<sequence>
<script>
if globalSplitServers:
replServer = _topologyReplServerList[indx]
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(), searchIndex)
</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=*)',
'changeNumberFilter' : chgNumberFilter,
'changelogCookie' : lastCookie
}
</call>
<script>
searchRC = RC
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
if ecl_mode == 'opends':
nextIndex = eclEntry['changelogcookie'][0]
else:
nextChgNumber = int(eclEntry['changenumber'][0]) + 1
nextIndex = str(nextChgNumber)
</script>
<message>
'Parsed changelog entry: \n%s' % eclEntry
</message>
<message>
'Index to use for the next ECL search: %s' % nextIndex
</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,
'changeNumber' : myChangeNumber,
'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 index for the next ECL search
if nextIndex:
searchIndex = nextIndex
nextIndex = None
# 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('%s - Modrdn_deleteoldrdn_true' % ecl_mode)">
<sequence>
<call function="'testCase_Preamble'"/>
<message>
'Replication: External Changelog: %s - Modrdn_deleteoldrdn_true. \
Verify modrdn operation is recorded properly in the \
external changelog on each repl server' % ecl_mode
</message>
<script>
modEntry = None
eclEntry = None
oldEntry = myEntry
newRdn = 'cn=b'
newEntry = Entry(newRdn, synchroSuffix)
</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 = RC
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'
if ecl_mode != 'opends':
myChangeNumber = searchIndex
else:
myChangeNumber = None
</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>
<script>
if ecl_mode == 'opends':
lastCookie = searchIndex
chgNumberFilter = None
else:
lastCookie = None
chgNumberFilter = """(changenumber>=%s)""" % searchIndex
</script>
<!-- Search changelog in the various replication servers -->
<iterate var="server"
in="_topologyServerList"
indexvar="indx">
<sequence>
<script>
if globalSplitServers:
replServer = _topologyReplServerList[indx]
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(), searchIndex)
</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=*)',
'changeNumberFilter' : chgNumberFilter,
'changelogCookie' : lastCookie
}
</call>
<script>
searchRC = RC
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
if ecl_mode == 'opends':
nextIndex = eclEntry['changelogcookie'][0]
else:
nextChgNumber = int(eclEntry['changenumber'][0]) + 1
nextIndex = str(nextChgNumber)
</script>
<message>
'Parsed changelog entry: \n%s' % eclEntry
</message>
<message>
'Index to use for the next ECL search: %s' % nextIndex
</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,
'changeNumber' : myChangeNumber,
'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 index for the next ECL search
if nextIndex:
searchIndex = nextIndex
nextIndex = None
# 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('%s - Modrdn_deleteoldrdn_false' % ecl_mode)">
<sequence>
<call function="'testCase_Preamble'"/>
<message>
'Replication: External Changelog: %s - Modrdn_deleteoldrdn_false. \
Verify modrdn operation is recorded properly in the \
external changelog on each repl server' % ecl_mode
</message>
<script>
modEntry = None
eclEntry = None
oldEntry = newEntry
newRdn = 'cn=c'
newEntry = Entry(newRdn, synchroSuffix)
</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 = RC
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'
if ecl_mode != 'opends':
myChangeNumber = searchIndex
else:
myChangeNumber = None
</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>
<script>
if ecl_mode == 'opends':
lastCookie = searchIndex
chgNumberFilter = None
else:
lastCookie = None
chgNumberFilter = """(changenumber>=%s)""" % searchIndex
</script>
<!-- Search changelog in the various replication servers -->
<iterate var="server"
in="_topologyServerList"
indexvar="indx">
<sequence>
<script>
if globalSplitServers:
replServer = _topologyReplServerList[indx]
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(), searchIndex)
</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=*)',
'changeNumberFilter' : chgNumberFilter,
'changelogCookie' : lastCookie
}
</call>
<script>
searchRC = RC
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
if ecl_mode == 'opends':
nextIndex = eclEntry['changelogcookie'][0]
else:
nextChgNumber = int(eclEntry['changenumber'][0]) + 1
nextIndex = str(nextChgNumber)
</script>
<message>
'Parsed changelog entry: \n%s' % eclEntry
</message>
<message>
'Index to use for the next ECL search: %s' % nextIndex
</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,
'changeNumber' : myChangeNumber,
'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 index for the next ECL search
if nextIndex:
searchIndex = nextIndex
nextIndex = None
# 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('%s - Delete_1' % ecl_mode)">
<sequence>
<call function="'testCase_Preamble'"/>
<message>
'Replication: External Changelog: %s - Delete_1. \
Verify delete operation is recorded properly in the \
external changelog on each repl server' % ecl_mode
</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 = RC
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
if ecl_mode != 'opends':
myChangeNumber = searchIndex
else:
myChangeNumber = None
</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>
<script>
if ecl_mode == 'opends':
lastCookie = searchIndex
chgNumberFilter = None
else:
lastCookie = None
chgNumberFilter = """(changenumber>=%s)""" % searchIndex
</script>
<!-- Search changelog in the various replication servers -->
<iterate var="server"
in="_topologyServerList"
indexvar="indx">
<sequence>
<script>
if globalSplitServers:
replServer = _topologyReplServerList[indx]
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(), searchIndex)
</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=*)',
'changeNumberFilter' : chgNumberFilter,
'changelogCookie' : lastCookie
}
</call>
<script>
searchRC = RC
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
if ecl_mode == 'opends':
nextIndex = eclEntry['changelogcookie'][0]
else:
nextChgNumber = int(eclEntry['changenumber'][0]) + 1
nextIndex = str(nextChgNumber)
</script>
<message>
'Parsed changelog entry: \n%s' % eclEntry
</message>
<message>
'Index to use for the next ECL search: %s' % nextIndex
</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,
'changeNumber' : myChangeNumber,
'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 index for the next ECL search
if nextIndex:
searchIndex = nextIndex
nextIndex = None
# 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('%s - Add_2' % ecl_mode)">
<sequence>
<call function="'testCase_Preamble'"/>
<message>
'Replication: External Changelog: %s - Add_2. \
Verify add operation (of and entry with userpassword) is \
recorded properly in the external changelog on each \
replication server' % ecl_mode
</message>
<!-- Add entry to "master" server -->
<script>
myEntry = Entry('cn=user', synchroSuffix)
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 = RC
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]
if ecl_mode != 'opends':
myChangeNumber = searchIndex
else:
myChangeNumber = None
</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>
<script>
if ecl_mode == 'opends':
lastCookie = searchIndex
chgNumberFilter = None
else:
lastCookie = None
chgNumberFilter = """(changenumber>=%s)""" % searchIndex
</script>
<!-- Search changelog in the various replication servers -->
<iterate var="server"
in="_topologyServerList"
indexvar="indx">
<sequence>
<script>
if globalSplitServers:
replServer = _topologyReplServerList[indx]
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(), searchIndex)
</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=*)',
'changeNumberFilter' : chgNumberFilter,
'changelogCookie' : lastCookie
}
</call>
<script>
searchRC = RC
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
if ecl_mode == 'opends':
nextIndex = eclEntry['changelogcookie'][0]
else:
nextChgNumber = int(eclEntry['changenumber'][0]) + 1
nextIndex = str(nextChgNumber)
</script>
<message>
'Parsed changelog entry: \n%s' % eclEntry
</message>
<message>
'Index to use for the next ECL search: %s' % nextIndex
</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,
'changeNumber' : myChangeNumber,
'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 index for the next ECL search
if nextIndex:
searchIndex = nextIndex
nextIndex = None
# 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('%s - Modify_replace_2' % ecl_mode)">
<sequence>
<call function="'testCase_Preamble'"/>
<message>
'Replication: External Changelog: %s - Modify_replace_2. \
Verify modify-replace operation as non directory manager is \
recorded properly in the external changelog on each repl server' \
% ecl_mode
</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 = RC
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])
if ecl_mode != 'opends':
myChangeNumber = searchIndex
else:
myChangeNumber = None
</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>
<script>
if ecl_mode == 'opends':
lastCookie = searchIndex
chgNumberFilter = None
else:
lastCookie = None
chgNumberFilter = """(changenumber>=%s)""" % searchIndex
</script>
<!-- Search changelog in the various replication servers -->
<iterate var="server"
in="_topologyServerList"
indexvar="indx">
<sequence>
<script>
if globalSplitServers:
replServer = _topologyReplServerList[indx]
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(), searchIndex)
</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=*)',
'changeNumberFilter' : chgNumberFilter,
'changelogCookie' : lastCookie
}
</call>
<script>
searchRC = RC
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
if ecl_mode == 'opends':
nextIndex = eclEntry['changelogcookie'][0]
else:
nextChgNumber = int(eclEntry['changenumber'][0]) + 1
nextIndex = str(nextChgNumber)
</script>
<message>
'Parsed changelog entry: \n%s' % eclEntry
</message>
<message>
'Index to use for the next ECL search: %s' % nextIndex
</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,
'changeNumber' : myChangeNumber,
'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 index for the next ECL search
if nextIndex:
searchIndex = nextIndex
nextIndex = None
# 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: Last index
#@TestID Last index
#@TestPurpose Verify the last index (lastExternalChangelogCookie
or lastChangenumber) value matches that of the last
external changelog entry
#@TestPreamble
#@TestSteps Modify entry on server A
#@TestSteps Verify servers in sync
#@TestSteps Read index from last changelog entry on each server
#@TestSteps Read lastExternalchangelogCookie/lastChangenumber
from root DSE entry
#@TestSteps Check last index value against last ECL entry one
#@TestPostamble
#@TestResult Success if the server synchronised and the
changelog entry value check succeeds
-->
<testcase name="getTestCaseName('%s - Last index' % ecl_mode)">
<sequence>
<call function="'testCase_Preamble'"/>
<message>
'Replication: External Changelog: %s - Last index. \
Verify the last index (lastExternalChangelogCookie or \
lastChangenumber) value matches that of the last external \
changelog entry' % ecl_mode
</message>
<script>
myEntryDn = 'cn=user,ou=People,%s' % synchroSuffix
newLoc = 'Montbonnot'
modEntry = None
eclEntry = None
</script>
<!-- Modify entry on "master" server -->
<call function="'modifyAnAttribute'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'dsInstanceHost' : masterHost,
'dsInstancePort' : master.getPort(),
'dsInstanceDn' : master.getRootDn(),
'dsInstancePswd' : master.getRootPwd(),
'DNToModify' : myEntryDn,
'attributeName' : 'l',
'newAttributeValue' : newLoc,
'changetype' : 'add'
}
</call>
<!-- Verify the synchronization of the trees among the servers in
the topology -->
<call function="'verifyTrees'">
[ clientHost, clientPath, master, consumerList, synchroSuffix ]
</call>
<script>
if ecl_mode == 'opends':
lastCookie = searchIndex
chgNumberFilter = None
else:
lastCookie = None
chgNumberFilter = """(changenumber>=%s)""" % searchIndex
</script>
<iterate var="server"
in="_topologyServerList"
indexvar="indx">
<sequence>
<!-- Read last index from root DSE (lastExternalChangelogCookie /
! lastChangenumber) -->
<script>
lastIndexAttr = None
lastIndexValue = None
if ecl_mode == 'opends':
lastIndexAttr = 'lastexternalchangelogcookie'
else:
lastIndexAttr = 'lastchangenumber'
serverPath = '%s/%s' % (server.getDir(), OPENDSNAME)
</script>
<call function="'ldapSearchWithScript'">
{ 'location' : server.getHostname(),
'dsPath' : serverPath,
'dsInstanceHost' : server.getHostname(),
'dsInstancePort' : server.getPort(),
'dsInstanceDn' : server.getRootDn(),
'dsInstancePswd' : server.getRootPwd(),
'dsScope' : 'base',
'dsBaseDN' : ' ',
'dsFilter' : 'objectclass=*',
'dsAttributes' : lastIndexAttr
}
</call>
<script>
searchRC = RC
searchResult = STAXResult[0][1]
</script>
<if expr="searchRC == 0">
<sequence>
<script>
lastIndexValue = None
pendingValue = 0
for line in searchResult.splitlines():
notBlank = (len(line.strip()) != 0)
if line.strip().lower().startswith(lastIndexAttr):
# line corresponds to lastIndexAttr:_lastIndexValue_
lastIndexValue = line[line.find(':') + 1:].lstrip()
pendingValue = 1
elif (notBlank and pendingValue):
lastIndexValue += line.lstrip()
elif pendingValue:
pendingValue = 0
break
</script>
<message>
'Last index read from root DSE entry %s attribute: %s' % \
(lastIndexAttr, lastIndexValue)
</message>
</sequence>
<else>
<message log="1" level="'Error'">
'Could not read root DSE entry from server %s:%s' % \
(server.getHostname(), server.getPort())
</message>
</else>
</if>
<!-- Search changelog in the various replication servers -->
<script>
if globalSplitServers:
replServer = _topologyReplServerList[indx]
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(), searchIndex)
</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=*)',
'changeNumberFilter' : chgNumberFilter,
'changelogCookie' : lastCookie
}
</call>
<script>
searchRC = RC
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
eclIndexValue = None
if ecl_mode == 'opends':
eclIndexValue = eclEntry['changelogcookie'][0]
nextIndex = eclEntry['changelogcookie'][0]
else:
eclIndexValue = eclEntry['changenumber'][0]
nextChgNumber = int(eclEntry['changenumber'][0]) + 1
nextIndex = str(nextChgNumber)
</script>
<message>
'Index to use for the next ECL search: %s' % nextIndex
</message>
<if expr="lastIndexValue != eclIndexValue">
<sequence>
<message log="1" level="'Error'">
'Last index %s:%s does not match value found in ECL \
entry %s : %s' % (lastIndexAttr, lastIndexValue,
eclEntry['dn'][0], eclIndexValue)
</message>
<call function="'testFailed'"/>
</sequence>
</if>
</sequence>
<else>
<message log="1" level="'Error'">
'Could not read changelog on replication server %s:%s' \
% (replServer.getHostname(), replServer.getPort())
</message>
</else>
</if>
</sequence>
</iterate>
<script>
# set the index for the next ECL search
if nextIndex:
searchIndex = nextIndex
nextIndex = None
# 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: Failover (stop)
#@TestID Failover (stop)
#@TestPurpose Verify the external changelog can cope with a server
failover (server stopped)
#@TestPreamble
#@TestSteps Stop "consumer" servers
#@TestSteps Modify entry on server A
#@TestSteps Read entry from ldap server
#@TestSteps Start "consumer" servers
#@TestSteps Modify entry on server A
#@TestSteps Read entry from ldap server
#@TestSteps Verify servers in sync
#@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('%s - Failover (stop)' % ecl_mode)">
<sequence>
<call function="'testCase_Preamble'"/>
<message>
'Replication: External Changelog: %s - Failover (stop). \
Verify the external changelog can cope with a server failover \
(server stopped)' % ecl_mode
</message>
<script>
myEntryDn = 'cn=user,ou=People,%s' % synchroSuffix
newDesc0 = 'Failover (stop) test - before server start'
newDesc1 = 'Failover (stop) test - after server start'
modEntries = []
modEntry = None
eclEntries = []
</script>
<!-- Stop the "consumer" servers -->
<call function="'stopServers'">
[consumerList]
</call>
<if expr="globalSplitServers">
<call function="'stopServers'">
[_topologyReplServerList[1:]]
</call>
</if>
<!-- Modify entry on "master" server -->
<call function="'modifyAnAttribute'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'dsInstanceHost' : masterHost,
'dsInstancePort' : master.getPort(),
'dsInstanceDn' : master.getRootDn(),
'dsInstancePswd' : master.getRootPwd(),
'DNToModify' : myEntryDn,
'attributeName' : 'description',
'newAttributeValue' : newDesc0,
'changetype' : 'replace'
}
</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' : myEntryDn,
'dsFilter' : 'objectclass=*',
'dsAttributes' : modOperationalAttrs
}
</call>
<script>
searchRC = RC
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>
modEntries.append(STAXResult)
</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>
<!-- Start the "consumer" servers -->
<call function="'startServers'">
[consumerList]
</call>
<if expr="globalSplitServers">
<call function="'startServers'">
[_topologyReplServerList[1:]]
</call>
</if>
<!-- Modify entry on "master" server -->
<call function="'modifyAnAttribute'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'dsInstanceHost' : masterHost,
'dsInstancePort' : master.getPort(),
'dsInstanceDn' : master.getRootDn(),
'dsInstancePswd' : master.getRootPwd(),
'DNToModify' : myEntryDn,
'attributeName' : 'description',
'newAttributeValue' : newDesc1,
'changetype' : 'replace'
}
</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' : myEntryDn,
'dsFilter' : 'objectclass=*',
'dsAttributes' : modOperationalAttrs
}
</call>
<script>
searchRC = RC
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>
modEntries.append(STAXResult)
</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>
<!-- Verify the synchronization of the trees among the servers in
the topology -->
<call function="'verifyTrees'">
[ clientHost, clientPath, master, consumerList, synchroSuffix ]
</call>
<script>
if ecl_mode == 'opends':
lastCookie = searchIndex
chgNumberFilter = None
else:
lastCookie = None
chgNumberFilter = """(changenumber>=%s)""" % searchIndex
</script>
<!-- Search changelog in the various replication servers -->
<iterate var="server"
in="_topologyServerList"
indexvar="indx">
<sequence>
<script>
if globalSplitServers:
replServer = _topologyReplServerList[indx]
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(), searchIndex)
</message>
<!-- Search for entry modifies -->
<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=*)',
'changeNumberFilter' : chgNumberFilter,
'changelogCookie' : lastCookie
}
</call>
<script>
searchRC = RC
searchResult = STAXResult[0][1]
</script>
<if expr="searchRC == 0">
<sequence>
<message>
'These are the ECL entries as read from server %s:%s: \n%s' \
% (replServer.getHostname(), replServer.getPort(),
searchResult)
</message>
<call function="'parseLdifEntries'">
{ 'ldifEntries' : searchResult }
</call>
<script>
eclEntries = STAXResult
</script>
<if expr="len(modEntries) != len(eclEntries)">
<sequence>
<message log="1" level="'Error'">
'Number of added entries %s does not match number of ECL \
entries %s' % (len(modEntries), len(eclEntries))
</message>
<call function="'testFailed'"/>
</sequence>
</if>
<iterate var="eclEntry"
in="eclEntries"
indexvar="i">
<sequence>
<script>
if ecl_mode == 'opends':
nextIndex = eclEntry['changelogcookie'][0]
else:
nextChgNumber = int(eclEntry['changenumber'][0]) + 1
nextIndex = str(nextChgNumber)
modEntry = modEntries[i]
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]
myDescription = modEntry['description'][0]
myChanges = []
myChanges.append(['replace', 'description', myDescription])
myChanges.append(['replace', 'modifiersname', myModifiersName])
myChanges.append(['replace', 'modifytimestamp', myModifyTimestamp])
if ecl_mode != 'opends':
myIntChangeNumber = int(searchIndex) + i
myChangeNumber = str(myIntChangeNumber)
else:
myChangeNumber = None
</script>
<message>
'Parsed changelog entry: \n%s' % eclEntry
</message>
<message>
'Index to use for the next ECL search: %s' % nextIndex
</message>
<if expr="modEntry and eclEntry">
<call function="'checkChangelogEntry'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'changelogEntry' : eclEntry,
'targetDN' : myTargetDN,
'changeNumber' : myChangeNumber,
'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)' % \
(myTargetDN, eclEntry['dn'][0])
</message>
<call function="'testFailed'"/>
</sequence>
</else>
</if>
</sequence>
</iterate>
</sequence>
<else>
<message log="1" level="'Error'">
'Could not read changelog on replication server %s:%s' \
% (replServer.getHostname(), replServer.getPort())
</message>
</else>
</if>
</sequence>
</iterate>
<script>
# set the index for the next ECL search
if nextIndex:
searchIndex = nextIndex
nextIndex = None
# reset variables, just in case
modEntries = []
moddEntry = None
eclEntries = []
eclEntry = None
</script>
<call function="'testCase_Postamble'"/>
</sequence>
</testcase>
<!--- Test Case information
#@TestMarker Replication External Changelog Tests
#@TestName Replication: External Changelog: Failover (kill)
#@TestID Failover (kill)
#@TestPurpose Verify the external changelog can cope with a server
failover (server killed)
#@TestPreamble
#@TestSteps Kill "consumer" servers
#@TestSteps Modify entry on server A
#@TestSteps Read entry from ldap server
#@TestSteps Start "consumer" servers
#@TestSteps Modify entry on server A
#@TestSteps Read entry from ldap server
#@TestSteps Verify servers in sync
#@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('%s - Failover (kill)' % ecl_mode)">
<sequence>
<call function="'testCase_Preamble'"/>
<message>
'Replication: External Changelog: %s - Failover (kill). \
Verify the external changelog can cope with a server failover \
(server killed)' % ecl_mode
</message>
<script>
myEntryDn = 'cn=user,ou=People,%s' % synchroSuffix
newDesc0 = 'Failover (kill) test - before server start'
newDesc1 = 'Failover (kill) test - after server start'
modEntries = []
modEntry = None
eclEntries = []
</script>
<!-- Kill the "consumer" servers -->
<paralleliterate var="server" in="consumerList" indexvar="i">
<sequence>
<script>
serverPath = '%s/%s' % (server.getDir(), OPENDSNAME)
if globalSplitServers:
replServer = _topologyReplServerList[i+1]
else:
replServer = server
replServerPath = '%s/%s' % (replServer.getDir(), OPENDSNAME)
</script>
<!-- Kill server (simulate failover?) -->
<call function="'killDs'">
{ 'location' : server.getHostname(),
'dsPath' : serverPath
}
</call>
<if expr="globalSplitServers">
<call function="'killDs'">
{ 'location' : replServer.getHostname(),
'dsPath' : replServerPath
}
</call>
</if>
</sequence>
</paralleliterate>
<!-- Modify entry on "master" server -->
<call function="'modifyAnAttribute'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'dsInstanceHost' : masterHost,
'dsInstancePort' : master.getPort(),
'dsInstanceDn' : master.getRootDn(),
'dsInstancePswd' : master.getRootPwd(),
'DNToModify' : myEntryDn,
'attributeName' : 'description',
'newAttributeValue' : newDesc0,
'changetype' : 'replace'
}
</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' : myEntryDn,
'dsFilter' : 'objectclass=*',
'dsAttributes' : modOperationalAttrs
}
</call>
<script>
searchRC = RC
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>
modEntries.append(STAXResult)
</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>
<!-- Start the "consumer" servers -->
<call function="'startServers'">
[consumerList]
</call>
<if expr="globalSplitServers">
<call function="'startServers'">
[_topologyReplServerList[1:]]
</call>
</if>
<!-- Modify entry on "master" server -->
<call function="'modifyAnAttribute'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'dsInstanceHost' : masterHost,
'dsInstancePort' : master.getPort(),
'dsInstanceDn' : master.getRootDn(),
'dsInstancePswd' : master.getRootPwd(),
'DNToModify' : myEntryDn,
'attributeName' : 'description',
'newAttributeValue' : newDesc1,
'changetype' : 'replace'
}
</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' : myEntryDn,
'dsFilter' : 'objectclass=*',
'dsAttributes' : modOperationalAttrs
}
</call>
<script>
searchRC = RC
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>
modEntries.append(STAXResult)
</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>
<!-- Verify the synchronization of the trees among the servers in
the topology -->
<call function="'verifyTrees'">
[ clientHost, clientPath, master, consumerList, synchroSuffix ]
</call>
<script>
if ecl_mode == 'opends':
lastCookie = searchIndex
chgNumberFilter = None
else:
lastCookie = None
chgNumberFilter = """(changenumber>=%s)""" % searchIndex
</script>
<!-- Search changelog in the various replication servers -->
<iterate var="server"
in="_topologyServerList"
indexvar="indx">
<sequence>
<script>
if globalSplitServers:
replServer = _topologyReplServerList[indx]
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(), searchIndex)
</message>
<!-- Search for entry modifies -->
<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=*)',
'changeNumberFilter' : chgNumberFilter,
'changelogCookie' : lastCookie
}
</call>
<script>
searchRC = RC
searchResult = STAXResult[0][1]
</script>
<if expr="searchRC == 0">
<sequence>
<message>
'These are the ECL entries as read from server %s:%s: \n%s' \
% (replServer.getHostname(), replServer.getPort(),
searchResult)
</message>
<call function="'parseLdifEntries'">
{ 'ldifEntries' : searchResult }
</call>
<script>
eclEntries = STAXResult
</script>
<if expr="len(modEntries) != len(eclEntries)">
<sequence>
<message log="1" level="'Error'">
'Number of added entries %s does not match number of ECL \
entries %s' % (len(modEntries), len(eclEntries))
</message>
<call function="'testFailed'"/>
</sequence>
</if>
<iterate var="eclEntry"
in="eclEntries"
indexvar="i">
<sequence>
<script>
if ecl_mode == 'opends':
nextIndex = eclEntry['changelogcookie'][0]
else:
nextChgNumber = int(eclEntry['changenumber'][0]) + 1
nextIndex = str(nextChgNumber)
modEntry = modEntries[i]
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]
myDescription = modEntry['description'][0]
myChanges = []
myChanges.append(['replace', 'description', myDescription])
myChanges.append(['replace', 'modifiersname', myModifiersName])
myChanges.append(['replace', 'modifytimestamp', myModifyTimestamp])
if ecl_mode != 'opends':
myIntChangeNumber = int(searchIndex) + i
myChangeNumber = str(myIntChangeNumber)
else:
myChangeNumber = None
</script>
<message>
'Parsed changelog entry: \n%s' % eclEntry
</message>
<message>
'Index to use for the next ECL search: %s' % nextIndex
</message>
<if expr="modEntry and eclEntry">
<call function="'checkChangelogEntry'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'changelogEntry' : eclEntry,
'targetDN' : myTargetDN,
'changeNumber' : myChangeNumber,
'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)' % \
(myTargetDN, eclEntry['dn'][0])
</message>
<call function="'testFailed'"/>
</sequence>
</else>
</if>
</sequence>
</iterate>
</sequence>
<else>
<message log="1" level="'Error'">
'Could not read changelog on replication server %s:%s' \
% (replServer.getHostname(), replServer.getPort())
</message>
</else>
</if>
</sequence>
</iterate>
<script>
# set the index for the next ECL search
if nextIndex:
searchIndex = nextIndex
nextIndex = None
# reset variables, just in case
modEntries = []
moddEntry = None
eclEntries = []
eclEntry = None
</script>
<call function="'testCase_Postamble'"/>
</sequence>
</testcase>
<!--- Test Case information
#@TestMarker Replication External Changelog Tests
#@TestName Replication: External Changelog: Multiple add
(single server)
#@TestID Multiple add (single server)
#@TestPurpose Verify multiple add operations on a single server
are recorded properly in the external changelog on
each replication server
#@TestPreamble
#@TestSteps Add multiple entries to server A
#@TestSteps Verify servers in sync
#@TestSteps Read entries from ldap server
#@TestSteps Read changelog entries on each repl server
#@TestSteps Check changelog entries against expected values and
order
#@TestPostamble
#@TestResult Success if the server synchronised and the
changelog entry value check succeeds
-->
<testcase name="getTestCaseName('%s - Multiple add (single server)' % ecl_mode)">
<sequence>
<call function="'testCase_Preamble'"/>
<message>
'Replication: External Changelog: %s - Multiple add (single server). \
Verify multiple add operations on a single server are recorded \
properly in the external changelog on each replication server' \
% ecl_mode
</message>
<!-- Add entry to "master" server -->
<script>
myEntries = []
for i in [1,2,3]:
myEntry = Entry('cn=user-%s' % i, synchroSuffix)
myEntry.addAttr('uid', 'U-%s' % i)
myEntry.addAttr('sn', 'Multiple add')
myEntries.append(myEntry)
addedEntries = []
eclEntries = []
</script>
<iterate var="myEntry" in="myEntries">
<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>
</iterate>
<!-- 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' : synchroSuffix,
'dsFilter' : 'sn=Multiple add',
'dsAttributes' : addOperationalAttrs
}
</call>
<script>
searchRC = RC
searchResult = STAXResult[0][1]
</script>
<if expr="searchRC == 0">
<sequence>
<message>
'These are the entries as read from server %s:%s: \n%s' % \
(masterHost, master.getPort(), searchResult)
</message>
<call function="'parseLdifEntries'">
{ 'ldifEntries' : searchResult }
</call>
<script>
addedEntries = STAXResult
</script>
</sequence>
<else>
<message log="1" level="'Error'">
'Could not read added entries from server %s:%s' % \
(masterHost, master.getPort())
</message>
</else>
</if>
<script>
if ecl_mode == 'opends':
lastCookie = searchIndex
chgNumberFilter = None
else:
lastCookie = None
chgNumberFilter = """(changenumber>=%s)""" % searchIndex
</script>
<!-- Search changelog in the various replication servers -->
<iterate var="server"
in="_topologyServerList"
indexvar="indx">
<sequence>
<script>
if globalSplitServers:
replServer = _topologyReplServerList[indx]
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(), searchIndex)
</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=*)',
'changeNumberFilter' : chgNumberFilter,
'changelogCookie' : lastCookie
}
</call>
<script>
searchRC = RC
searchResult = STAXResult[0][1]
</script>
<if expr="searchRC == 0">
<sequence>
<message>
'These are the ECL entries as read from server %s:%s: \n%s' \
% (replServer.getHostname(), replServer.getPort(),
searchResult)
</message>
<call function="'parseLdifEntries'">
{ 'ldifEntries' : searchResult }
</call>
<script>
eclEntries = STAXResult
</script>
<if expr="len(addedEntries) != len(eclEntries)">
<sequence>
<message log="1" level="'Error'">
'Number of added entries %s does not match number of ECL \
entries %s' % (len(addedEntries), len(eclEntries))
</message>
<call function="'testFailed'"/>
</sequence>
</if>
<iterate var="eclEntry"
in="eclEntries"
indexvar="i">
<sequence>
<script>
if ecl_mode == 'opends':
nextIndex = eclEntry['changelogcookie'][0]
else:
nextChgNumber = int(eclEntry['changenumber'][0]) + 1
nextIndex = str(nextChgNumber)
addedEntry = addedEntries[i]
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]
if ecl_mode != 'opends':
myIntChangeNumber = int(searchIndex) + i
myChangeNumber = str(myIntChangeNumber)
else:
myChangeNumber = None
</script>
<message>
'Parsed changelog entry: \n%s' % eclEntry
</message>
<message>
'Index to use for the next ECL search: %s' % nextIndex
</message>
<if expr="addedEntry and eclEntry">
<call function="'checkChangelogEntry'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'changelogEntry' : eclEntry,
'targetDN' : myTargetDN,
'changeNumber' : myChangeNumber,
'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)' % \
(myTargetDN, eclEntry['dn'][0])
</message>
<call function="'testFailed'"/>
</sequence>
</else>
</if>
</sequence>
</iterate>
</sequence>
<else>
<message log="1" level="'Error'">
'Could not read changelog on replication server %s:%s' \
% (replServer.getHostname(), replServer.getPort())
</message>
</else>
</if>
</sequence>
</iterate>
<script>
# set the index for the next ECL search
if nextIndex:
searchIndex = nextIndex
nextIndex = None
# reset variables, just in case
addedEntries = []
addedEntry = None
eclEntries = []
eclEntry = None
</script>
<call function="'testCase_Postamble'"/>
</sequence>
</testcase>
<!--- Test Case information
#@TestMarker Replication External Changelog Tests
#@TestName Replication: External Changelog: Multiple add
(multiple servers)
#@TestID Multiple add (multiple servers)
#@TestPurpose Verify multiple add operations on multiple servers
are recorded properly in the external changelog on
each replication server
#@TestPreamble
#@TestSteps Add multiple entries to different servers
#@TestSteps Verify servers in sync
#@TestSteps Read entries from ldap server
#@TestSteps Read changelog entries on each repl server
#@TestSteps Check changelog entries against expected values and
order
#@TestPostamble
#@TestResult Success if the server synchronised and the
changelog entry value check succeeds
-->
<testcase name="getTestCaseName('%s - Multiple add (multiple servers)' % ecl_mode)">
<sequence>
<call function="'testCase_Preamble'"/>
<message>
'Replication: External Changelog: %s - Multiple add (multiple servers). \
Verify multiple add operations on multiple servers are recorded \
properly in the external changelog on each replication server' \
% ecl_mode
</message>
<!-- Add entries to servers -->
<script>
myEntries = []
for i in [1,2,3]:
myEntry = Entry('cn=NEWuser-%s' % i, synchroSuffix)
myEntry.addAttr('uid', 'NEWU-%s' % i)
myEntry.addAttr('sn', 'NEW Multiple add')
myEntries.append(myEntry)
addedEntries = []
eclEntries = []
</script>
<iterate var="myEntry"
in="myEntries"
indexvar="indx">
<sequence>
<script>
serverIndex = indx % len(_topologyServerList)
server = _topologyServerList[serverIndex]
</script>
<message>
'Adding entry %s to server %s:%s)' % \
(myEntry.getDn(), server.getHostname(), server.getPort())
</message>
<call function="'addAnEntry'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'dsInstanceHost' : server.getHostname(),
'dsInstancePort' : server.getPort(),
'dsInstanceDn' : server.getRootDn(),
'dsInstancePswd' : server.getRootPwd(),
'DNToAdd' : myEntry.getDn(),
'listAttributes' : myEntry.getAttrList()
}
</call>
</sequence>
</iterate>
<!-- 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' : synchroSuffix,
'dsFilter' : 'sn=NEW Multiple add',
'dsAttributes' : addOperationalAttrs
}
</call>
<script>
searchRC = RC
searchResult = STAXResult[0][1]
</script>
<if expr="searchRC == 0">
<sequence>
<message>
'These are the entries as read from server %s:%s: \n%s' % \
(masterHost, master.getPort(), searchResult)
</message>
<call function="'parseLdifEntries'">
{ 'ldifEntries' : searchResult }
</call>
<script>
addedEntries = STAXResult
</script>
</sequence>
<else>
<message log="1" level="'Error'">
'Could not read added entries from server %s:%s' % \
(masterHost, master.getPort())
</message>
</else>
</if>
<script>
if ecl_mode == 'opends':
lastCookie = searchIndex
chgNumberFilter = None
else:
lastCookie = None
chgNumberFilter = """(changenumber>=%s)""" % searchIndex
</script>
<!-- Search changelog in the various replication servers -->
<iterate var="server"
in="_topologyServerList"
indexvar="indx">
<sequence>
<script>
if globalSplitServers:
replServer = _topologyReplServerList[indx]
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(), searchIndex)
</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=*)',
'changeNumberFilter' : chgNumberFilter,
'changelogCookie' : lastCookie
}
</call>
<script>
searchRC = RC
searchResult = STAXResult[0][1]
</script>
<if expr="searchRC == 0">
<sequence>
<message>
'These are the ECL entries as read from server %s:%s: \n%s' \
% (replServer.getHostname(), replServer.getPort(),
searchResult)
</message>
<call function="'parseLdifEntries'">
{ 'ldifEntries' : searchResult }
</call>
<script>
eclEntries = STAXResult
</script>
<if expr="len(addedEntries) != len(eclEntries)">
<sequence>
<message log="1" level="'Error'">
'Number of added entries %s does not match number of ECL \
entries %s' % (len(addedEntries), len(eclEntries))
</message>
<call function="'testFailed'"/>
</sequence>
</if>
<iterate var="eclEntry"
in="eclEntries"
indexvar="i">
<sequence>
<script>
if ecl_mode == 'opends':
nextIndex = eclEntry['changelogcookie'][0]
else:
nextChgNumber = int(eclEntry['changenumber'][0]) + 1
nextIndex = str(nextChgNumber)
addedEntry = addedEntries[i]
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]
if ecl_mode != 'opends':
myIntChangeNumber = int(searchIndex) + i
myChangeNumber = str(myIntChangeNumber)
else:
myChangeNumber = None
</script>
<message>
'Parsed changelog entry: \n%s' % eclEntry
</message>
<message>
'Index to use for the next ECL search: %s' % nextIndex
</message>
<if expr="addedEntry and eclEntry">
<call function="'checkChangelogEntry'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'changelogEntry' : eclEntry,
'targetDN' : myTargetDN,
'changeNumber' : myChangeNumber,
'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)' % \
(myTargetDN, eclEntry['dn'][0])
</message>
<call function="'testFailed'"/>
</sequence>
</else>
</if>
</sequence>
</iterate>
</sequence>
<else>
<message log="1" level="'Error'">
'Could not read changelog on replication server %s:%s' \
% (replServer.getHostname(), replServer.getPort())
</message>
</else>
</if>
</sequence>
</iterate>
<script>
# set the index for the next ECL search
if nextIndex:
searchIndex = nextIndex
nextIndex = None
# reset variables, just in case
addedEntries = []
addedEntry = None
eclEntries = []
eclEntry = None
</script>
<call function="'testCase_Postamble'"/>
</sequence>
</testcase>
<!--- Test Case information
#@TestMarker Replication External Changelog Tests
#@TestName Replication: External Changelog: Multiple modify
(multiple servers)
#@TestID Multiple modify (multiple servers)
#@TestPurpose Verify multiple mod operations on multiple servers
are recorded properly in the external changelog on
each replication server
#@TestPreamble
#@TestSteps Modify multiple entries to different servers
#@TestSteps Verify servers in sync
#@TestSteps Read entries from ldap server
#@TestSteps Read changelog entries on each repl server
#@TestSteps Check changelog entries against expected values and
order
#@TestPostamble
#@TestResult Success if the server synchronised and the
changelog entry value check succeeds
-->
<testcase name="getTestCaseName('%s - Multiple modify (multiple servers)' % ecl_mode)">
<sequence>
<call function="'testCase_Preamble'"/>
<message>
'Replication: External Changelog: %s - Multiple modify (multiple \
servers). \
Verify multiple mod operations on multiple servers are recorded \
properly in the external changelog on each replication server' \
% ecl_mode
</message>
<!-- Add entries to servers -->
<script>
myEntryDn = 'cn=user,ou=People,%s' % synchroSuffix
myTelephonenumbers = ['11-11-11','22-22-22','33-33-33','44-44-44']
modEntries = []
modEntry = None
eclEntries = []
</script>
<iterate var="myTelephonenumber"
in="myTelephonenumbers"
indexvar="indx">
<sequence>
<script>
serverIndex = indx % len(_topologyServerList)
server = _topologyServerList[serverIndex]
serverPath = '%s/%s' % (server.getDir(), OPENDSNAME)
</script>
<message>
'Adding telephonenumber %s to entry %s on server %s:%s' % \
(myTelephonenumber, myEntryDn,
server.getHostname(), server.getPort())
</message>
<!-- Modify entry on one of the servers -->
<call function="'modifyAnAttribute'">
{ 'location' : server.getHostname(),
'dsPath' : serverPath,
'dsInstanceHost' : server.getHostname(),
'dsInstancePort' : server.getPort(),
'dsInstanceDn' : server.getRootDn(),
'dsInstancePswd' : server.getRootPwd(),
'DNToModify' : myEntryDn,
'attributeName' : 'telephonenumber',
'newAttributeValue' : myTelephonenumber,
'changetype' : 'add'
}
</call>
<!-- Retrieve entry information for checkChangelogEntry's sake -->
<call function="'ldapSearchWithScript'">
{ 'location' : server.getHostname(),
'dsPath' : serverPath,
'dsInstanceHost' : server.getHostname(),
'dsInstancePort' : server.getPort(),
'dsInstanceDn' : server.getRootDn(),
'dsInstancePswd' : server.getRootPwd(),
'dsBaseDN' : myEntryDn,
'dsFilter' : 'objectclass=*',
'dsAttributes' : modOperationalAttrs
}
</call>
<script>
searchRC = RC
searchResult = STAXResult[0][1]
</script>
<if expr="searchRC == 0">
<sequence>
<message>
'This is the entry as read from server %s:%s: \n%s' % \
(server.getHostname(), server.getPort(), searchResult)
</message>
<call function="'parseLdifEntry'">
{ 'ldifEntry' : searchResult }
</call>
<script>
modEntries.append(STAXResult)
</script>
</sequence>
<else>
<message log="1" level="'Error'">
'Could not read modified entries from server %s:%s' % \
(server.getHostname(), server.getPort())
</message>
</else>
</if>
</sequence>
</iterate>
<!-- Verify the synchronization of the trees among the servers in
the topology -->
<call function="'verifyTrees'">
[ clientHost, clientPath, master, consumerList, synchroSuffix ]
</call>
<script>
if ecl_mode == 'opends':
lastCookie = searchIndex
chgNumberFilter = None
else:
lastCookie = None
chgNumberFilter = """(changenumber>=%s)""" % searchIndex
</script>
<!-- Search changelog in the various replication servers -->
<iterate var="server"
in="_topologyServerList"
indexvar="indx">
<sequence>
<script>
if globalSplitServers:
replServer = _topologyReplServerList[indx]
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(), searchIndex)
</message>
<!-- Search for entry modifies -->
<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=*)',
'changeNumberFilter' : chgNumberFilter,
'changelogCookie' : lastCookie
}
</call>
<script>
searchRC = RC
searchResult = STAXResult[0][1]
</script>
<if expr="searchRC == 0">
<sequence>
<message>
'These are the ECL entries as read from server %s:%s: \n%s' \
% (replServer.getHostname(), replServer.getPort(),
searchResult)
</message>
<call function="'parseLdifEntries'">
{ 'ldifEntries' : searchResult }
</call>
<script>
eclEntries = STAXResult
</script>
<if expr="len(modEntries) != len(eclEntries)">
<sequence>
<message log="1" level="'Error'">
'Number of added entries %s does not match number of ECL \
entries %s' % (len(modEntries), len(eclEntries))
</message>
<call function="'testFailed'"/>
</sequence>
</if>
<iterate var="eclEntry"
in="eclEntries"
indexvar="i">
<sequence>
<script>
if ecl_mode == 'opends':
nextIndex = eclEntry['changelogcookie'][0]
else:
nextChgNumber = int(eclEntry['changenumber'][0]) + 1
nextIndex = str(nextChgNumber)
modEntry = modEntries[i]
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]
myTelephonenumber = myTelephonenumbers[i]
myChanges = []
myChanges.append(['add', 'telephonenumber', myTelephonenumber])
myChanges.append(['replace', 'modifiersname', myModifiersName])
myChanges.append(['replace', 'modifytimestamp', myModifyTimestamp])
if ecl_mode != 'opends':
myIntChangeNumber = int(searchIndex) + i
myChangeNumber = str(myIntChangeNumber)
else:
myChangeNumber = None
</script>
<message>
'Parsed changelog entry: \n%s' % eclEntry
</message>
<message>
'Index to use for the next ECL search: %s' % nextIndex
</message>
<if expr="modEntry and eclEntry">
<call function="'checkChangelogEntry'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'changelogEntry' : eclEntry,
'targetDN' : myTargetDN,
'changeNumber' : myChangeNumber,
'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)' % \
(myTargetDN, eclEntry['dn'][0])
</message>
<call function="'testFailed'"/>
</sequence>
</else>
</if>
</sequence>
</iterate>
</sequence>
<else>
<message log="1" level="'Error'">
'Could not read changelog on replication server %s:%s' \
% (replServer.getHostname(), replServer.getPort())
</message>
</else>
</if>
</sequence>
</iterate>
<script>
# set the index for the next ECL search
if nextIndex:
searchIndex = nextIndex
nextIndex = None
# reset variables, just in case
modEntries = []
moddEntry = None
eclEntries = []
eclEntry = None
</script>
<call function="'testCase_Postamble'"/>
</sequence>
</testcase>
<!--- Test Case information
#@TestMarker Replication External Changelog Tests
#@TestName Replication: External Changelog: Two suffixes (one
replicated, one non-replicated)
#@TestID Two suffixes (one replicated, one non-replicated)
#@TestPurpose Verify external changelog only cares about
replicated suffix
#@TestPreamble
#@TestSteps Add entry (old suffix) 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
#@TestSteps Add new suffix on server A
#@TestSteps Add entry (new suffix) to server A
#@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('%s - Two suffixes (one replicated, one non-replicated)' % ecl_mode)">
<sequence>
<call function="'testCase_Preamble'"/>
<message>
'Replication: External Changelog: %s - Two suffixes (one \
replicated, one non-replicated). \
Verify external changelog only cares about replicated suffix' % ecl_mode
</message>
<!-- Add entry to replicated suffix on "master" server -->
<script>
myEntry = Entry('cn=entry', synchroSuffix)
myEntry.addAttr('sn', 'Replicated')
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 = RC
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]
if ecl_mode != 'opends':
myChangeNumber = searchIndex
else:
myChangeNumber = None
</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>
<script>
if ecl_mode == 'opends':
lastCookie = searchIndex
chgNumberFilter = None
else:
lastCookie = None
chgNumberFilter = """(changenumber>=%s)""" % searchIndex
</script>
<!-- Search changelog in the various replication servers -->
<iterate var="server"
in="_topologyServerList"
indexvar="indx">
<sequence>
<script>
if globalSplitServers:
replServer = _topologyReplServerList[indx]
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(), searchIndex)
</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=*)',
'changeNumberFilter' : chgNumberFilter,
'changelogCookie' : lastCookie
}
</call>
<script>
searchRC = RC
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
if ecl_mode == 'opends':
nextIndex = eclEntry['changelogcookie'][0]
else:
nextChgNumber = int(eclEntry['changenumber'][0]) + 1
nextIndex = str(nextChgNumber)
</script>
<message>
'Parsed changelog entry: \n%s' % eclEntry
</message>
<message>
'Index to use for the next ECL search: %s' % nextIndex
</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,
'changeNumber' : myChangeNumber,
'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 index for the next ECL search
if nextIndex:
searchIndex = nextIndex
nextIndex = None
# reset variables, just in case
addedEntry = None
eclEntry = None
</script>
<!-- Add entry to non-replicated suffix on "master" server -->
<script>
newSuffix = 'o=new_suffix_no_repl'
newRootEntryAttrs = []
newRootEntryAttrs.append('objectclass:top')
newRootEntryAttrs.append('objectclass:organization')
newPeopleEntryAttrs = []
newPeopleEntryAttrs.append('objectclass:top')
newPeopleEntryAttrs.append('objectclass:organizationalunit')
myNewEntry = Entry('cn=entry', newSuffix)
myNewEntry.addAttr('sn', 'Not replicated')
addedEntries = []
eclEntries = []
</script>
<!-- Add new suffix to userRoot backend on "master" server -->
<call function="'dsconfigSet'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'dsInstanceHost' : masterHost,
'dsInstanceAdminPort' : master.getAdminPort(),
'dsInstanceDn' : master.getRootDn(),
'dsInstancePswd' : master.getRootPwd(),
'objectName' : 'backend',
'propertyType' : 'backend',
'propertyName' : 'userRoot',
'modifyType' : 'add',
'attributeName' : 'base-dn',
'attributeValue' : newSuffix
}
</call>
<call function="'addAnEntry'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'dsInstanceHost' : masterHost,
'dsInstancePort' : master.getPort(),
'dsInstanceDn' : master.getRootDn(),
'dsInstancePswd' : master.getRootPwd(),
'DNToAdd' : newSuffix,
'listAttributes' : newRootEntryAttrs
}
</call>
<call function="'addAnEntry'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'dsInstanceHost' : masterHost,
'dsInstancePort' : master.getPort(),
'dsInstanceDn' : master.getRootDn(),
'dsInstancePswd' : master.getRootPwd(),
'DNToAdd' : 'ou=People,%s' % newSuffix,
'listAttributes' : newPeopleEntryAttrs
}
</call>
<call function="'addAnEntry'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'dsInstanceHost' : masterHost,
'dsInstancePort' : master.getPort(),
'dsInstanceDn' : master.getRootDn(),
'dsInstancePswd' : master.getRootPwd(),
'DNToAdd' : myNewEntry.getDn(),
'listAttributes' : myNewEntry.getAttrList()
}
</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' : newSuffix,
'dsFilter' : 'objectclass=*',
'dsAttributes' : addOperationalAttrs
}
</call>
<script>
searchRC = RC
searchResult = STAXResult[0][1]
</script>
<if expr="searchRC == 0">
<sequence>
<message>
'These are the entries as read from server %s:%s: \n%s' % \
(masterHost, master.getPort(), searchResult)
</message>
<call function="'parseLdifEntries'">
{ 'ldifEntries' : searchResult }
</call>
<script>
addedEntries = STAXResult
</script>
</sequence>
<else>
<message log="1" level="'Error'">
'Could not read added entries from server %s:%s' % \
(masterHost, master.getPort())
</message>
</else>
</if>
<script>
if ecl_mode == 'opends':
lastCookie = searchIndex
chgNumberFilter = None
else:
lastCookie = None
chgNumberFilter = """(changenumber>=%s)""" % searchIndex
</script>
<!-- Search changelog in the various replication servers ;
! newSuffix not replicated => expect no new changelog entry -->
<iterate var="server"
in="_topologyServerList"
indexvar="indx">
<sequence>
<script>
if ecl_mode != 'opends':
# Issue 4309: draft-mode search for new changes returns error
# if no new changes since last search
myKnownIssue = '4309'
else:
myKnownIssue = None
if globalSplitServers:
replServer = _topologyReplServerList[indx]
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(), searchIndex)
</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=*)',
'changeNumberFilter' : chgNumberFilter,
'changelogCookie' : lastCookie,
'knownIssue' : myKnownIssue
}
</call>
<script>
searchRC = RC
searchResult = STAXResult[0][1]
</script>
<if expr="searchRC == 0">
<sequence>
<message>
'These are the ECL entries as read from server %s:%s: \n%s' \
% (replServer.getHostname(), replServer.getPort(),
searchResult)
</message>
<call function="'parseLdifEntries'">
{ 'ldifEntries' : searchResult }
</call>
<script>
eclEntries = STAXResult
eclEntriesNb = len(eclEntries)
if searchResult.find('Failed to match a replication state') != -1:
# Search returned an error => no ECL entries
eclEntriesNb = 0
# newSuffix not replicated => expect no new entry in ECL
expectedNb = 0
</script>
<message>
'Server %s:%s : ECL entries = %s ; Expected = %s' % \
(replServer.getHostname(), replServer.getPort(),
eclEntriesNb, expectedNb)
</message>
<if expr="eclEntriesNb != expectedNb">
<sequence>
<message log="1" level="'Error'">
'Number of ECL entries %s does not match number of \
expected entries %s' % (eclEntriesNb, expectedNb)
</message>
<call function="'testFailed'"/>
<!-- if eclEntries != 0, read them for the sake of
! updating the searchIndex with the latest value -->
<iterate var="eclEntry"
in="eclEntries"
indexvar="i">
<sequence>
<script>
if ecl_mode == 'opends':
nextIndex = eclEntry['changelogcookie'][0]
else:
nextChgNumber = int(eclEntry['changenumber'][0]) + 1
nextIndex = str(nextChgNumber)
</script>
<message>
'Index to use for the next ECL search: %s' % nextIndex
</message>
</sequence>
</iterate>
</sequence>
</if>
</sequence>
<else>
<message log="1" level="'Error'">
'Could not read changelog on replication server %s:%s' \
% (replServer.getHostname(), replServer.getPort())
</message>
</else>
</if>
</sequence>
</iterate>
<script>
# set the index for the next ECL search
if nextIndex:
searchIndex = nextIndex
nextIndex = None
# reset variables, just in case
addedEntries = []
addedEntry = None
eclEntries = []
eclEntry = None
</script>
<call function="'testCase_Postamble'"/>
</sequence>
</testcase>
<!--- Test Case information
#@TestMarker Replication External Changelog Tests
#@TestName Replication: External Changelog: Two suffixes (both
replicated)
#@TestID Two suffixes (both replicated)
#@TestPurpose Verify external changelog can manage several
suffixes
#@TestPreamble
#@TestSteps Add entry (old suffix) to server A
#@TestSteps Verify servers in sync
#@TestSteps Add new suffix on servers
#@TestSteps Enable replication for new suffix
#@TestSteps Add entries (new suffix) to server A
#@TestSteps Verify servers in sync
#@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('%s - Two suffixes (both replicated)' % ecl_mode)">
<sequence>
<call function="'testCase_Preamble'"/>
<message>
'Replication: External Changelog: %s - Two suffixes (both \
replicated). \
Verify external changelog can manage several suffixes' % ecl_mode
</message>
<!-- Add entry to replicated suffix on "master" server -->
<script>
myEntry = Entry('cn=entry A', synchroSuffix)
myEntry.addAttr('sn', 'Replicated')
addedEntries = []
addedEntry = None
eclEntry = None
firstEclEntryList = []
</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 = RC
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>
addedEntries.append(STAXResult)
</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>
<script>
if ecl_mode == 'opends':
lastCookie = searchIndex
chgNumberFilter = None
else:
lastCookie = None
chgNumberFilter = """(changenumber>=%s)""" % searchIndex
</script>
<!-- Search changelog in the various replication servers -->
<iterate var="server"
in="_topologyServerList"
indexvar="indx">
<sequence>
<script>
if globalSplitServers:
replServer = _topologyReplServerList[indx]
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(), searchIndex)
</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=*)',
'changeNumberFilter' : chgNumberFilter,
'changelogCookie' : lastCookie
}
</call>
<script>
searchRC = RC
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
firstEclEntryList.append(eclEntry)
if ecl_mode == 'opends':
nextIndex = eclEntry['changelogcookie'][0]
else:
nextChgNumber = int(eclEntry['changenumber'][0]) + 1
nextIndex = str(nextChgNumber)
</script>
<message>
'Parsed changelog entry: \n%s' % eclEntry
</message>
<message>
'Index to use for the next ECL search: %s' % nextIndex
</message>
</sequence>
<else>
<message log="1" level="'Error'">
'Could not read changelog on replication server %s:%s' \
% (replServer.getHostname(), replServer.getPort())
</message>
</else>
</if>
</sequence>
</iterate>
<!-- Add entries to non-replicated suffix on "master" server -->
<script>
newReplSuffix = 'o=new_suffix_repl'
newRootEntryAttrs = []
newRootEntryAttrs.append('objectclass:top')
newRootEntryAttrs.append('objectclass:organization')
newPeopleEntryAttrs = []
newPeopleEntryAttrs.append('objectclass:top')
newPeopleEntryAttrs.append('objectclass:organizationalunit')
myNewEntry = Entry('cn=entry A', newReplSuffix)
myNewEntry.addAttr('sn', 'Replicated')
eclEntries = []
</script>
<!-- Add new suffix to userRoot backend on servers -->
<iterate var="server"
in="_topologyServerList"
indexvar="indx">
<sequence>
<script>
serverPath = '%s/%s' % (server.getDir(), OPENDSNAME)
</script>
<call function="'dsconfigSet'">
{ 'location' : server.getHostname(),
'dsPath' : serverPath,
'dsInstanceHost' : server.getHostname(),
'dsInstanceAdminPort' : server.getAdminPort(),
'dsInstanceDn' : server.getRootDn(),
'dsInstancePswd' : server.getRootPwd(),
'objectName' : 'backend',
'propertyType' : 'backend',
'propertyName' : 'userRoot',
'modifyType' : 'add',
'attributeName' : 'base-dn',
'attributeValue' : newReplSuffix
}
</call>
<if expr="indx != 0">
<!-- Call enableReplication except for "master" server -->
<sequence>
<script>
if master.isOnlyLdapServer():
masterReplPort = None
else:
masterReplPort = masterReplicationServer.getPort()
if server.isOnlyLdapServer():
serverReplPort = None
else:
replicationServer = server.getChangelogServer()
serverReplPort = replicationServer.getPort()
replicatedDnList = [newReplSuffix]
</script>
<message>
'Enable replication for server:\nHost: %s\nLdap port: %s\n\
Replication port: %s\nReplicated DN list: %s' \
% (server.getHostname(), server.getPort(),
serverReplPort, replicatedDnList)
</message>
<call function="'enableReplication'">
{ 'location' : clientHost,
'dsPath' : clientPath,
'refInstanceHost' : masterHost,
'refInstanceAdminPort' : master.getAdminPort(),
'refInstanceDn' : master.getRootDn(),
'refInstancePswd' : master.getRootPwd(),
'refReplicationPort' : masterReplPort,
'refSecureReplication' : secureReplication,
'refOnlyLdapServer' : master.isOnlyLdapServer(),
'refOnlyReplServer' : master.isOnlyReplServer(),
'dsInstanceHost' : server.getHostname(),
'dsInstanceAdminPort' : server.getAdminPort(),
'dsInstanceDn' : server.getRootDn(),
'dsInstancePswd' : server.getRootPwd(),
'dsReplicationPort' : serverReplPort,
'dsSecureReplication' : secureReplication,
'dsOnlyLdapServer' : server.isOnlyLdapServer(),
'dsOnlyReplServer' : server.isOnlyReplServer(),
'replicationDnList' : replicatedDnList
}
</call>
</sequence>
</if>
</sequence>
</iterate>
<script>
firstSearchIndex = searchIndex
# set the index for the next ECL search
if nextIndex:
searchIndex = nextIndex
nextIndex = None
</script>
<if expr="ecl_mode == 'opends'">
<sequence>
<!-- New replicated suffix added => resync required
! Check searching ECL with old (single-suffix) cookie returns
! error and requests resync -->
<script>
lastCookie = searchIndex
chgNumberFilter = None
</script>
<!-- Search changelog in the various replication servers -->
<iterate var="server"
in="_topologyServerList"
indexvar="indx">
<sequence>
<script>
if globalSplitServers:
replServer = _topologyReplServerList[indx]
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(), searchIndex)
</message>
<!-- Search for entry add - expect error (RC=1) -->
<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=*)',
'changeNumberFilter' : chgNumberFilter,
'changelogCookie' : lastCookie,
'expectedRC' : 1
}
</call>
<script>
searchRC = RC
searchResult = STAXResult[0][1]
</script>
<if expr="searchRC == 0">
<sequence>
<message>
'This is the ECL search result on server %s:%s: \n%s' \
% (replServer.getHostname(), replServer.getPort(),
searchResult)
</message>
<call function="'searchString'">
{ 'expectedString' : 'resync',
'returnString' : searchResult
}
</call>
</sequence>
</if>
</sequence>
</iterate>
<!-- New replicated suffix added => resync required =>
! Retrieve lastExternalChangelogCookie from root DSE -->
<call function="'ldapSearchWithScript'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'dsInstanceHost' : masterHost,
'dsInstancePort' : master.getPort(),
'dsInstanceDn' : master.getRootDn(),
'dsInstancePswd' : master.getRootPwd(),
'dsScope' : 'base',
'dsBaseDN' : ' ',
'dsFilter' : 'objectclass=*',
'dsAttributes' : 'lastExternalChangelogCookie'
}
</call>
<script>
searchRC = RC
searchResult = STAXResult[0][1]
</script>
<if expr="searchRC == 0">
<sequence>
<script>
lastECLCookie = None
pendingValue = 0
for line in searchResult.splitlines():
notBlank = (len(line.strip()) != 0)
if line.strip().lower().startswith('lastexternalchangelogcookie'):
# line corresponds to lastExternalChangelogCookie:_cookie_
lastECLCookie = line[line.find(':') + 1:].lstrip()
pendingValue = 1
elif (notBlank and pendingValue):
lastECLCookie += line.lstrip()
elif pendingValue:
pendingValue = 0
break
searchIndex = lastECLCookie
</script>
<message>
'New index read from root DSE entry lastExternalChangelogCookie \
attribute: %s' % searchIndex
</message>
</sequence>
<else>
<message log="1" level="'Error'">
'Could not read root DSE entry from server %s:%s' % \
(masterHost, master.getPort())
</message>
</else>
</if>
</sequence>
</if>
<!-- Add new entries -->
<call function="'addAnEntry'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'dsInstanceHost' : masterHost,
'dsInstancePort' : master.getPort(),
'dsInstanceDn' : master.getRootDn(),
'dsInstancePswd' : master.getRootPwd(),
'DNToAdd' : newReplSuffix,
'listAttributes' : newRootEntryAttrs
}
</call>
<call function="'addAnEntry'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'dsInstanceHost' : masterHost,
'dsInstancePort' : master.getPort(),
'dsInstanceDn' : master.getRootDn(),
'dsInstancePswd' : master.getRootPwd(),
'DNToAdd' : 'ou=People,%s' % newReplSuffix,
'listAttributes' : newPeopleEntryAttrs
}
</call>
<call function="'addAnEntry'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'dsInstanceHost' : masterHost,
'dsInstancePort' : master.getPort(),
'dsInstanceDn' : master.getRootDn(),
'dsInstancePswd' : master.getRootPwd(),
'DNToAdd' : myNewEntry.getDn(),
'listAttributes' : myNewEntry.getAttrList()
}
</call>
<!-- Verify the synchronization of the trees among the servers in
the topology -->
<call function="'verifyTrees'">
[ clientHost, clientPath, master, consumerList, newReplSuffix ]
</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' : newReplSuffix,
'dsFilter' : 'objectclass=*',
'dsAttributes' : addOperationalAttrs
}
</call>
<script>
searchRC = RC
searchResult = STAXResult[0][1]
</script>
<if expr="searchRC == 0">
<sequence>
<message>
'These are the entries as read from server %s:%s: \n%s' % \
(masterHost, master.getPort(), searchResult)
</message>
<call function="'parseLdifEntries'">
{ 'ldifEntries' : searchResult }
</call>
<script>
addedEntries += STAXResult
</script>
</sequence>
<else>
<message log="1" level="'Error'">
'Could not read added entries from server %s:%s' % \
(masterHost, master.getPort())
</message>
</else>
</if>
<script>
if ecl_mode == 'opends':
lastCookie = searchIndex
chgNumberFilter = None
else:
lastCookie = None
chgNumberFilter = """(changenumber>=%s)""" % searchIndex
</script>
<!-- Search changelog in the various replication servers -->
<iterate var="server"
in="_topologyServerList"
indexvar="indx">
<sequence>
<script>
if globalSplitServers:
replServer = _topologyReplServerList[indx]
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(), searchIndex)
</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=*)',
'changeNumberFilter' : chgNumberFilter,
'changelogCookie' : lastCookie
}
</call>
<script>
searchRC = RC
searchResult = STAXResult[0][1]
</script>
<if expr="searchRC == 0">
<sequence>
<message>
'These are the ECL entries as read from server %s:%s: \n%s' \
% (replServer.getHostname(), replServer.getPort(),
searchResult)
</message>
<call function="'parseLdifEntries'">
{ 'ldifEntries' : searchResult }
</call>
<script>
eclEntries = [firstEclEntryList[indx]] + STAXResult
eclEntriesNb = len(eclEntries)
expectedNb = len(addedEntries)
</script>
<message>
'Server %s:%s : ECL entries = %s ; Expected = %s' % \
(replServer.getHostname(), replServer.getPort(),
eclEntriesNb, expectedNb)
</message>
<if expr="eclEntriesNb != expectedNb">
<sequence>
<message log="1" level="'Error'">
'Number of ECL entries %s does not match number of \
expected entries %s' % (eclEntriesNb, expectedNb)
</message>
<call function="'testFailed'"/>
</sequence>
</if>
<iterate var="eclEntry"
in="eclEntries"
indexvar="i">
<sequence>
<script>
if ecl_mode == 'opends':
nextIndex = eclEntry['changelogcookie'][0]
else:
nextChgNumber = int(eclEntry['changenumber'][0]) + 1
nextIndex = str(nextChgNumber)
addedEntry = addedEntries[i]
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]
if ecl_mode != 'opends':
myIntChangeNumber = int(firstSearchIndex) + i
myChangeNumber = str(myIntChangeNumber)
else:
myChangeNumber = None
</script>
<message>
'Parsed changelog entry: \n%s' % eclEntry
</message>
<message>
'Index to use for the next ECL search: %s' % nextIndex
</message>
<if expr="addedEntry and eclEntry">
<call function="'checkChangelogEntry'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'changelogEntry' : eclEntry,
'targetDN' : myTargetDN,
'changeNumber' : myChangeNumber,
'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)' % \
(myTargetDN, eclEntry['dn'][0])
</message>
<call function="'testFailed'"/>
</sequence>
</else>
</if>
</sequence>
</iterate>
</sequence>
<else>
<message log="1" level="'Error'">
'Could not read changelog on replication server %s:%s' \
% (replServer.getHostname(), replServer.getPort())
</message>
</else>
</if>
</sequence>
</iterate>
<script>
# set the index for the next ECL search
if nextIndex:
searchIndex = nextIndex
nextIndex = None
# reset variables, just in case
addedEntries = []
addedEntry = None
eclEntries = []
eclEntry = None
firstEclEntryList = []
</script>
<call function="'testCase_Postamble'"/>
</sequence>
</testcase>
<!--- Test Case information
#@TestMarker Replication External Changelog Tests
#@TestName Replication: External Changelog: Two suffixes,
alternate adds
#@TestID Two suffixes, alternate adds
#@TestPurpose Verify external changelog can manage several
suffixes
#@TestPreamble
#@TestSteps Add entries to both suffixes on different servers
alternately
#@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('%s - Two suffixes, alternate adds' % ecl_mode)">
<sequence>
<call function="'testCase_Preamble'"/>
<message>
'Replication: External Changelog: %s - Two suffixes, alternate \
adds. \
Verify external changelog can manage several suffixes' % ecl_mode
</message>
<!-- Add entries to servers -->
<script>
newReplSuffix = 'o=new_suffix_repl'
myEntries = []
myEntry = Entry('cn=entry 1', synchroSuffix)
myEntry.addAttr('sn', 'Alternate')
myEntries.append(myEntry)
myEntry = Entry('cn=entry 2', newReplSuffix)
myEntry.addAttr('sn', 'Alternate')
myEntries.append(myEntry)
myEntry = Entry('cn=entry 3', synchroSuffix)
myEntry.addAttr('sn', 'Alternate')
myEntries.append(myEntry)
myEntry = Entry('cn=entry 4', newReplSuffix)
myEntry.addAttr('sn', 'Alternate')
myEntries.append(myEntry)
myEntry = Entry('cn=entry 5', newReplSuffix)
myEntry.addAttr('sn', 'Alternate')
myEntries.append(myEntry)
addedEntries = []
eclEntries = []
</script>
<iterate var="myEntry"
in="myEntries"
indexvar="indx">
<sequence>
<script>
serverIndex = indx % len(_topologyServerList)
server = _topologyServerList[serverIndex]
</script>
<message>
'Adding entry %s to server %s:%s)' % \
(myEntry.getDn(), server.getHostname(), server.getPort())
</message>
<call function="'addAnEntry'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'dsInstanceHost' : server.getHostname(),
'dsInstancePort' : server.getPort(),
'dsInstanceDn' : server.getRootDn(),
'dsInstancePswd' : server.getRootPwd(),
'DNToAdd' : myEntry.getDn(),
'listAttributes' : myEntry.getAttrList()
}
</call>
</sequence>
</iterate>
<!-- Verify the synchronization of the trees among the servers in
the topology -->
<call function="'verifyTrees'">
[ clientHost, clientPath, master, consumerList, synchroSuffix ]
</call>
<!-- Verify the synchronization of the trees among the servers in
the topology -->
<call function="'verifyTrees'">
[ clientHost, clientPath, master, consumerList, newReplSuffix ]
</call>
<script>
if ecl_mode == 'opends':
lastCookie = searchIndex
chgNumberFilter = None
else:
lastCookie = None
chgNumberFilter = """(changenumber>=%s)""" % searchIndex
</script>
<!-- synchroSuffix -->
<!-- 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' : synchroSuffix,
'dsFilter' : 'sn=Alternate',
'dsAttributes' : addOperationalAttrs
}
</call>
<script>
searchRC = RC
searchResult = STAXResult[0][1]
</script>
<if expr="searchRC == 0">
<sequence>
<message>
'These are the entries as read from server %s:%s: \n%s' % \
(masterHost, master.getPort(), searchResult)
</message>
<call function="'parseLdifEntries'">
{ 'ldifEntries' : searchResult }
</call>
<script>
addedEntries = STAXResult
</script>
</sequence>
<else>
<message log="1" level="'Error'">
'Could not read added entries from server %s:%s' % \
(masterHost, master.getPort())
</message>
</else>
</if>
<!-- Search changelog in the various replication servers ;
! search for synchroSuffix changes -->
<script>
if ecl_mode == 'opends':
# ECL entry DN: cn=_replicationCSN_,_suffix_,cn=changelog
eclSearchBaseDn = '%s,cn=changelog' % synchroSuffix
eclSearchFilter = '(objectclass=*)'
else:
# ECL entry DN: cn=_changenumber_,cn=changelog
# => suffix information sound on targetDN attribute
eclSearchBaseDn = 'cn=changelog'
eclSearchFilter = '(targetdn=*%s)' % synchroSuffix
</script>
<iterate var="server"
in="_topologyServerList"
indexvar="indx">
<sequence>
<script>
if globalSplitServers:
replServer = _topologyReplServerList[indx]
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(), searchIndex)
</message>
<!-- Search for entry adds in synchroSuffix -->
<call function="'SearchExternalChangelog'">
{ 'location' : replServer.getHostname(),
'dsPath' : replServerPath,
'dsInstanceHost' : replServer.getHostname(),
'dsInstancePort' : replServer.getPort(),
'dsInstanceDn' : replServer.getRootDn(),
'dsInstancePswd' : replServer.getRootPwd(),
'dsScope' : 'subordinate',
'dsBaseDN' : eclSearchBaseDn,
'dsFilter' : eclSearchFilter,
'changeNumberFilter' : chgNumberFilter,
'changelogCookie' : lastCookie
}
</call>
<script>
searchRC = RC
searchResult = STAXResult[0][1]
</script>
<if expr="searchRC == 0">
<sequence>
<message>
'These are the ECL entries for suffix %s as read from \
server %s:%s: \n%s' \
% (synchroSuffix, replServer.getHostname(),
replServer.getPort(), searchResult)
</message>
<call function="'parseLdifEntries'">
{ 'ldifEntries' : searchResult }
</call>
<script>
eclEntries = STAXResult
eclEntriesNb = len(eclEntries)
# two new updates on suffix synchroSuffix =>
expectedNb = 2
</script>
<message>
'Server %s:%s - Suffix: %s : ECL entries = %s ; Expected \
= %s' % \
(replServer.getHostname(), replServer.getPort(),
synchroSuffix, eclEntriesNb, expectedNb)
</message>
<if expr="eclEntriesNb != expectedNb">
<sequence>
<message log="1" level="'Error'">
'Number of ECL entries %s does not match number of \
expected entries %s' % (eclEntriesNb, expectedNb)
</message>
<call function="'testFailed'"/>
</sequence>
</if>
<iterate var="eclEntry"
in="eclEntries"
indexvar="i">
<sequence>
<script>
if ecl_mode == 'opends':
nextIndex = eclEntry['changelogcookie'][0]
else:
nextChgNumber = int(eclEntry['changenumber'][0]) + 1
nextIndex = str(nextChgNumber)
addedEntry = addedEntries[i]
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]
if ecl_mode != 'opends':
# synchroSuffix changes: 1st and 3rd
# (searchIndex = index of 1st change)
myIntChangeNumber = int(searchIndex) + i*2
myChangeNumber = str(myIntChangeNumber)
else:
myChangeNumber = None
</script>
<message>
'Parsed changelog entry: \n%s' % eclEntry
</message>
<message>
'Index to use for the next ECL search: %s' % nextIndex
</message>
<if expr="addedEntry and eclEntry">
<call function="'checkChangelogEntry'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'changelogEntry' : eclEntry,
'targetDN' : myTargetDN,
'changeNumber' : myChangeNumber,
'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)' % \
(myTargetDN, eclEntry['dn'][0])
</message>
<call function="'testFailed'"/>
</sequence>
</else>
</if>
</sequence>
</iterate>
</sequence>
<else>
<message log="1" level="'Error'">
'Could not read changelog on replication server %s:%s' \
% (replServer.getHostname(), replServer.getPort())
</message>
</else>
</if>
</sequence>
</iterate>
<!-- newReplSuffix -->
<!-- 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' : newReplSuffix,
'dsFilter' : 'sn=Alternate',
'dsAttributes' : addOperationalAttrs
}
</call>
<script>
searchRC = RC
searchResult = STAXResult[0][1]
</script>
<if expr="searchRC == 0">
<sequence>
<message>
'These are the entries as read from server %s:%s: \n%s' % \
(masterHost, master.getPort(), searchResult)
</message>
<call function="'parseLdifEntries'">
{ 'ldifEntries' : searchResult }
</call>
<script>
addedEntries = STAXResult
</script>
</sequence>
<else>
<message log="1" level="'Error'">
'Could not read added entries from server %s:%s' % \
(masterHost, master.getPort())
</message>
</else>
</if>
<!-- Search changelog in the various replication servers;
! search for newReplSuffix changes -->
<script>
if ecl_mode == 'opends':
# ECL entry DN: cn=_replicationCSN_,_suffix_,cn=changelog
eclSearchBaseDn = '%s,cn=changelog' % newReplSuffix
eclSearchFilter = '(objectclass=*)'
else:
# ECL entry DN: cn=_changenumber_,cn=changelog
# => suffix information sound on targetDN attribute
eclSearchBaseDn = 'cn=changelog'
eclSearchFilter = '(targetdn=*%s)' % newReplSuffix
</script>
<iterate var="server"
in="_topologyServerList"
indexvar="indx">
<sequence>
<script>
if globalSplitServers:
replServer = _topologyReplServerList[indx]
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(), searchIndex)
</message>
<!-- Search for entry adds in newReplSuffix -->
<call function="'SearchExternalChangelog'">
{ 'location' : replServer.getHostname(),
'dsPath' : replServerPath,
'dsInstanceHost' : replServer.getHostname(),
'dsInstancePort' : replServer.getPort(),
'dsInstanceDn' : replServer.getRootDn(),
'dsInstancePswd' : replServer.getRootPwd(),
'dsScope' : 'subordinate',
'dsBaseDN' : eclSearchBaseDn,
'dsFilter' : eclSearchFilter,
'changeNumberFilter' : chgNumberFilter,
'changelogCookie' : lastCookie
}
</call>
<script>
searchRC = RC
searchResult = STAXResult[0][1]
</script>
<if expr="searchRC == 0">
<sequence>
<message>
'These are the ECL entries for suffix %s as read from \
server %s:%s: \n%s' \
% (synchroSuffix, replServer.getHostname(),
replServer.getPort(), searchResult)
</message>
<call function="'parseLdifEntries'">
{ 'ldifEntries' : searchResult }
</call>
<script>
eclEntries = STAXResult
eclEntriesNb = len(eclEntries)
# three new updates on suffix newReplSuffix =>
expectedNb = 3
</script>
<message>
'Server %s:%s - Suffix: %s : ECL entries = %s ; Expected \
= %s' % \
(replServer.getHostname(), replServer.getPort(),
newReplSuffix, eclEntriesNb, expectedNb)
</message>
<if expr="eclEntriesNb != expectedNb">
<sequence>
<message log="1" level="'Error'">
'Number of ECL entries %s does not match number of \
expected entries %s' % (eclEntriesNb, expectedNb)
</message>
<call function="'testFailed'"/>
</sequence>
</if>
<iterate var="eclEntry"
in="eclEntries"
indexvar="i">
<sequence>
<script>
if ecl_mode == 'opends':
nextIndex = eclEntry['changelogcookie'][0]
else:
nextChgNumber = int(eclEntry['changenumber'][0]) + 1
nextIndex = str(nextChgNumber)
addedEntry = addedEntries[i]
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]
if ecl_mode != 'opends':
# newReplSuffix changes: 2nd, 4th and 5th
# (searchIndex = index of 1st change)
if i == 0:
myIntChangeNumber = int(searchIndex) + 1
elif i == 1:
myIntChangeNumber = int(searchIndex) + 3
elif i == 2:
myIntChangeNumber = int(searchIndex) + 4
myChangeNumber = str(myIntChangeNumber)
else:
myChangeNumber = None
</script>
<message>
'Parsed changelog entry: \n%s' % eclEntry
</message>
<message>
'Index to use for the next ECL search: %s' % nextIndex
</message>
<if expr="addedEntry and eclEntry">
<call function="'checkChangelogEntry'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'changelogEntry' : eclEntry,
'targetDN' : myTargetDN,
'changeNumber' : myChangeNumber,
'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)' % \
(myTargetDN, eclEntry['dn'][0])
</message>
<call function="'testFailed'"/>
</sequence>
</else>
</if>
</sequence>
</iterate>
</sequence>
<else>
<message log="1" level="'Error'">
'Could not read changelog on replication server %s:%s' \
% (replServer.getHostname(), replServer.getPort())
</message>
</else>
</if>
</sequence>
</iterate>
<script>
# set the index for the next ECL search
if nextIndex:
searchIndex = nextIndex
nextIndex = None
# reset variables, just in case
addedEntries = []
addedEntry = None
eclEntries = []
eclEntry = None
</script>
<call function="'testCase_Postamble'"/>
</sequence>
</testcase>
<!-- Clean new suffixes on servers -->
<!-- Clean newReplSuffix changes from changelog -->
<call function="'preInitializeReplication'">
{ 'location' : masterHost,
'dsPath' : masterPath,
'dsInstanceHost' : masterHost,
'dsInstanceAdminPort' : master.getAdminPort(),
'localOnly' : False,
'replicationDnList' : [newReplSuffix],
'adminUID' : adminUID,
'adminPswd' : adminPswd
}
</call>
<iterate var="server"
in="_topologyServerList"
indexvar="indx">
<sequence>
<script>
newSuffx = "o=new_suffix_no_repl"
newReplSuffix = "o=new_suffix_repl"
serverPath = '%s/%s' % (server.getDir(), OPENDSNAME)
</script>
<!-- Disable replication for newReplSuffix -->
<message>
'Disable replication for suffix %s on server %s:%s' % \
(newReplSuffix, server.getHostname(), server.getPort())
</message>
<call function="'disableReplication'">
{ 'location' : server.getHostname(),
'dsPath' : serverPath,
'dsInstanceHost' : server.getHostname(),
'dsInstanceAdminPort' : server.getAdminPort(),
'replicationDnList' : [newReplSuffix]
}
</call>
<!-- Remove newReplSuffix -->
<message>
'Remove suffix %s on server %s:%s' % \
(newReplSuffix, server.getHostname(), server.getPort())
</message>
<call function="'dsconfigSet'">
{ 'location' : server.getHostname(),
'dsPath' : serverPath,
'dsInstanceHost' : server.getHostname(),
'dsInstanceAdminPort' : server.getAdminPort(),
'dsInstanceDn' : server.getRootDn(),
'dsInstancePswd' : server.getRootPwd(),
'objectName' : 'backend',
'propertyType' : 'backend',
'propertyName' : 'userRoot',
'modifyType' : 'remove',
'attributeName' : 'base-dn',
'attributeValue' : newReplSuffix
}
</call>
<!-- Remove newSuffix (only present on "master" server) -->
<if expr="indx == 0">
<sequence>
<message>
'Remove suffix %s on server %s:%s' % \
(newSuffix, server.getHostname(), server.getPort())
</message>
<call function="'dsconfigSet'">
{ 'location' : server.getHostname(),
'dsPath' : serverPath,
'dsInstanceHost' : server.getHostname(),
'dsInstanceAdminPort' : server.getAdminPort(),
'dsInstanceDn' : server.getRootDn(),
'dsInstancePswd' : server.getRootPwd(),
'objectName' : 'backend',
'propertyType' : 'backend',
'propertyName' : 'userRoot',
'modifyType' : 'remove',
'attributeName' : 'base-dn',
'attributeValue' : newSuffix
}
</call>
</sequence>
</if>
</sequence>
</iterate>
</sequence>
</function>
</stax>