[389-ds-base] 02/02: Ticket 49540 - FIx compiler warning in ldif2ldbm
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
mreynolds pushed a commit to branch 389-ds-base-1.3.8
in repository 389-ds-base.
commit de73f4f6d492b43c42170edb8c375b7fb25d4cb4
Author: Mark Reynolds <mreynolds(a)redhat.com>
AuthorDate: Tue Jan 15 13:55:18 2019 -0500
Ticket 49540 - FIx compiler warning in ldif2ldbm
https://pagure.io/389-ds-base/issue/49540
Reviewed by: mreynolds(one line commit rule)
(cherry picked from commit 58be90b8bf96a7a0e10740b122035ea03fa13e0f)
(cherry picked from commit c9580477ffe22a08c0094378e81a6927d0dc4ffc)
---
ldap/servers/slapd/back-ldbm/ldif2ldbm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
index 69a2af9..11c020a 100644
--- a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
+++ b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
@@ -713,7 +713,7 @@ ldbm_back_ldif2ldbm(Slapi_PBlock *pb)
uint64_t refcnt;
refcnt = slapi_counter_get_value(inst->inst_ref_count);
if (refcnt > 0) {
- slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldif2ldbm", "ldbm: '%s' there are %d pending operation(s)."
+ slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldif2ldbm", "ldbm: '%s' there are %" PRIu64 " pending operation(s)."
" Import can not proceed until they are completed.\n",
inst->inst_name,
refcnt);
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years, 2 months
[389-ds-base] 01/02: Ticket 50117 - after certain failed import operation, impossible to replay an import operation
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
mreynolds pushed a commit to branch 389-ds-base-1.3.8
in repository 389-ds-base.
commit a56280287432406fd8258bf7ba1617c891a507b1
Author: Thierry Bordaz <tbordaz(a)redhat.com>
AuthorDate: Fri Jan 4 12:24:56 2019 +0100
Ticket 50117 - after certain failed import operation, impossible to replay an import operation
Bug Description:
At the beginning of an import, a flag is set to mark the target backend is busy.
Then import tests if there are pending operations. If such operations exist the import can not proceed and fails.
The problem is that in such case of pending operations, the import fails without resetting the busy flag.
It let the backend busy (until next reboot) and prevent new import.
Fix Description:
It needs to reset the busy flag if there are pending operations
https://pagure.io/389-ds-base/issue/50117
Reviewed by: Mark Reynolds, William Brown
Platforms tested: F27
Flag Day: no
Doc impact: no
(cherry picked from commit ff00b07402747aac403478a157adab75e306d7d1)
(cherry picked from commit 630940ec119a90c3bbfc7cd3464eb02ab779b474)
---
ldap/servers/slapd/back-ldbm/ldif2ldbm.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
index 16b87ee..69a2af9 100644
--- a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
+++ b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
@@ -704,12 +704,22 @@ ldbm_back_ldif2ldbm(Slapi_PBlock *pb)
}
/* check if an import/restore is already ongoing... */
- if ((instance_set_busy(inst) != 0) ||
- (slapi_counter_get_value(inst->inst_ref_count) > 0)) {
+ if ((instance_set_busy(inst) != 0)) {
slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldif2ldbm", "ldbm: '%s' is already in the middle of "
"another task and cannot be disturbed.\n",
inst->inst_name);
return -1;
+ } else {
+ uint64_t refcnt;
+ refcnt = slapi_counter_get_value(inst->inst_ref_count);
+ if (refcnt > 0) {
+ slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldif2ldbm", "ldbm: '%s' there are %d pending operation(s)."
+ " Import can not proceed until they are completed.\n",
+ inst->inst_name,
+ refcnt);
+ instance_set_not_busy(inst);
+ return -1;
+ }
}
if ((task_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE)) {
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years, 2 months
[389-ds-base] branch 389-ds-base-1.4.0 updated: Ticket 49873 - Contention on virtual attribute lookup
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
tbordaz pushed a commit to branch 389-ds-base-1.4.0
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.4.0 by this push:
new 6f87fab Ticket 49873 - Contention on virtual attribute lookup
6f87fab is described below
commit 6f87fab42db4bf084c4d9fa32897e7175ba1ef82
Author: Thierry Bordaz <tbordaz(a)redhat.com>
AuthorDate: Tue Jan 15 11:13:42 2019 +0100
Ticket 49873 - Contention on virtual attribute lookup
Bug Description:
During lookup of the virtual attribute table (filter evaluation and returned attribute)
the lock is acquired many times in read. For example it is acquired for each targetfilter aci and for
each evaluated entry.
Unfortunately RW lock is expensive and appears frequently on pstacks.
The lock exists because the table can be updated but update is very rare (addition of a new service provider).
So it slows down general proceeding for exceptional events.
Fix Description:
The fix is to acquire/release the read lock at the operation level and set a per-cpu flag, so that later lookup
would just check the flag.
https://pagure.io/389-ds-base/issue/49873
Reviewed by: Ludwig Krispenz, William Brown (thanks !!)
Platforms tested: F27
Flag Day: no
Doc impact: no
---
ldap/servers/slapd/connection.c | 1 +
ldap/servers/slapd/opshared.c | 6 +++
ldap/servers/slapd/proto-slap.h | 3 ++
ldap/servers/slapd/psearch.c | 1 +
ldap/servers/slapd/vattr.c | 82 ++++++++++++++++++++++++++++++++++-------
5 files changed, 80 insertions(+), 13 deletions(-)
diff --git a/ldap/servers/slapd/connection.c b/ldap/servers/slapd/connection.c
index 8b88568..fcc46cd 100644
--- a/ldap/servers/slapd/connection.c
+++ b/ldap/servers/slapd/connection.c
@@ -1509,6 +1509,7 @@ connection_threadmain()
long bypasspollcnt = 0;
enable_nunc_stans = config_get_enable_nunc_stans();
+ vattr_global_lock_init();
#if defined(hpux)
/* Arrange to ignore SIGPIPE signals. */
SIGNAL(SIGPIPE, SIG_IGN);
diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c
index e791a90..8b895a1 100644
--- a/ldap/servers/slapd/opshared.c
+++ b/ldap/servers/slapd/opshared.c
@@ -243,6 +243,7 @@ op_shared_search(Slapi_PBlock *pb, int send_result)
int pr_idx = -1;
Slapi_DN *orig_sdn = NULL;
int free_sdn = 0;
+ PRBool vattr_lock_acquired = PR_FALSE;
be_list[0] = NULL;
referral_list[0] = NULL;
@@ -528,6 +529,8 @@ op_shared_search(Slapi_PBlock *pb, int send_result)
}
slapi_pblock_set(pb, SLAPI_BACKEND_COUNT, &index);
+ vattr_rdlock();
+ vattr_lock_acquired = PR_TRUE;
if (be) {
slapi_pblock_set(pb, SLAPI_BACKEND, be);
@@ -983,6 +986,9 @@ free_and_return:
} else if (be_single) {
slapi_be_Unlock(be_single);
}
+ if (vattr_lock_acquired) {
+ vattr_unlock();
+ }
free_and_return_nolock:
slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, &rc);
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
index ca946fb..2029f41 100644
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -1419,6 +1419,9 @@ void subentry_create_filter(Slapi_Filter **filter);
* vattr.c
*/
void vattr_init(void);
+void vattr_global_lock_init(void);
+void vattr_rdlock();
+void vattr_unlock();
void vattr_cleanup(void);
/*
diff --git a/ldap/servers/slapd/psearch.c b/ldap/servers/slapd/psearch.c
index 8ad268a..e7b97a7 100644
--- a/ldap/servers/slapd/psearch.c
+++ b/ldap/servers/slapd/psearch.c
@@ -267,6 +267,7 @@ ps_send_results(void *arg)
Operation *pb_op = NULL;
g_incr_active_threadcnt();
+ vattr_global_lock_init();
slapi_pblock_get(ps->ps_pblock, SLAPI_CONNECTION, &pb_conn);
slapi_pblock_get(ps->ps_pblock, SLAPI_OPERATION, &pb_op);
diff --git a/ldap/servers/slapd/vattr.c b/ldap/servers/slapd/vattr.c
index f7c473a..155afca 100644
--- a/ldap/servers/slapd/vattr.c
+++ b/ldap/servers/slapd/vattr.c
@@ -102,6 +102,16 @@ int vattr_basic_sp_init();
void **statechange_api;
+struct _vattr_map
+{
+ Slapi_RWLock *lock;
+ PLHashTable *hashtable; /* Hash table */
+};
+typedef struct _vattr_map vattr_map;
+
+static vattr_map *the_map = NULL;
+static PRUintn thread_private_global_vattr_lock;
+
/* Housekeeping Functions, called by server startup/shutdown code */
/* Called on server startup, init all structures etc */
@@ -109,6 +119,7 @@ void
vattr_init()
{
statechange_api = 0;
+ PR_NewThreadPrivateIndex(&thread_private_global_vattr_lock, NULL);
vattr_map_create();
#ifdef VATTR_TEST_CODE
@@ -116,6 +127,60 @@ vattr_init()
#endif
}
+void
+vattr_global_lock_init()
+{
+ if (thread_private_global_vattr_lock) {
+ PR_SetThreadPrivate(thread_private_global_vattr_lock, (void *) 0);
+ }
+}
+/* The map lock can be acquired recursively. So only the first rdlock
+ * will acquire the lock.
+ * A optimization acquires it at high level (op_shared_search), so that
+ * later calls during the operation processing will just increase/decrease a counter.
+ */
+void
+vattr_rdlock()
+{
+ if (thread_private_global_vattr_lock) {
+ int nb_acquire = (int) PR_GetThreadPrivate(thread_private_global_vattr_lock);
+
+ if (nb_acquire == 0) {
+ /* The lock was not held just acquire it */
+ slapi_rwlock_rdlock(the_map->lock);
+ }
+ nb_acquire++;
+ PR_SetThreadPrivate(thread_private_global_vattr_lock, (void *) nb_acquire);
+ } else {
+ slapi_rwlock_rdlock(the_map->lock);
+ }
+}
+/* The map lock can be acquired recursively. So only the last unlock
+ * will release the lock.
+ * A optimization acquires it at high level (op_shared_search), so that
+ * later calls during the operation processing will just increase/decrease a counter.
+ */
+void
+vattr_unlock()
+{
+ if (thread_private_global_vattr_lock) {
+ int nb_acquire = (int) PR_GetThreadPrivate(thread_private_global_vattr_lock);
+
+ if (nb_acquire >= 1) {
+ nb_acquire--;
+ if (nb_acquire == 0) {
+ slapi_rwlock_unlock(the_map->lock);
+ }
+ PR_SetThreadPrivate(thread_private_global_vattr_lock, (void *) nb_acquire);
+ } else {
+ slapi_log_err(SLAPI_LOG_CRIT,
+ "vattr_unlock", "The lock was not acquire. We should not be here\n");
+ PR_ASSERT(nb_acquire >= 1);
+ }
+ } else {
+ slapi_rwlock_unlock(the_map->lock);
+ }
+}
/* Called on server shutdown, free all structures, inform service providers that we're going down etc */
void
vattr_cleanup()
@@ -1811,15 +1876,6 @@ typedef struct _vattr_map_entry vattr_map_entry;
vattr_map_entry test_entry = {NULL};
-struct _vattr_map
-{
- Slapi_RWLock *lock;
- PLHashTable *hashtable; /* Hash table */
-};
-typedef struct _vattr_map vattr_map;
-
-static vattr_map *the_map = NULL;
-
static PRIntn
vattr_hash_compare_keys(const void *v1, const void *v2)
{
@@ -1939,11 +1995,11 @@ vattr_map_lookup(const char *type_to_find, vattr_map_entry **result)
}
/* Get the reader lock */
- slapi_rwlock_rdlock(the_map->lock);
+ vattr_rdlock();
*result = (vattr_map_entry *)PL_HashTableLookupConst(the_map->hashtable,
(void *)basetype);
/* Release ze lock */
- slapi_rwlock_unlock(the_map->lock);
+ vattr_unlock();
if (tmp) {
slapi_ch_free_string(&tmp);
@@ -2131,7 +2187,7 @@ slapi_vattr_schema_check_type(Slapi_Entry *e, char *type)
objAttrValue *obj;
if (0 == vattr_map_lookup(type, &map_entry)) {
- slapi_rwlock_rdlock(the_map->lock);
+ vattr_rdlock();
obj = map_entry->objectclasses;
@@ -2148,7 +2204,7 @@ slapi_vattr_schema_check_type(Slapi_Entry *e, char *type)
obj = obj->pNext;
}
- slapi_rwlock_unlock(the_map->lock);
+ vattr_unlock();
}
slapi_valueset_free(vs);
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years, 2 months
[389-ds-base] branch 389-ds-base-1.3.7 updated: Ticket 49658 - In replicated topology a single-valued attribute can diverge
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
tbordaz pushed a commit to branch 389-ds-base-1.3.7
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.3.7 by this push:
new 407e89e Ticket 49658 - In replicated topology a single-valued attribute can diverge
407e89e is described below
commit 407e89e338c981c31bf1920c1ed28575a69de6e0
Author: Thierry Bordaz <tbordaz(a)redhat.com>
AuthorDate: Tue May 15 16:45:56 2018 +0200
Ticket 49658 - In replicated topology a single-valued attribute can diverge
Bug Description:
When deleting a specific value of a single valued attribute,
the deleted value can be erronously resurrected.
Fix Description:
This second fix is a rewrite of entry state resolution.
The original function (resolve_attribute_state_single_valued) implemented
a main algorythm but it was heavily merged with resolution of specific cases.
It was too difficult to make the function understandable and preserving
the handling of the specific cases.
The risk of that rewrite fix is that I can not guarantee it fully covers
the set of specific cases
https://pagure.io/389-ds-base/issue/49658
Reviewed by: William Brown (Thanks !!)
Platforms tested: F27
Flag Day: no
Doc impact: no
---
dirsrvtests/tests/tickets/ticket49658_test.py | 4264 +++++++++++++++++++++++++
ldap/servers/slapd/entrywsi.c | 404 ++-
2 files changed, 4521 insertions(+), 147 deletions(-)
diff --git a/dirsrvtests/tests/tickets/ticket49658_test.py b/dirsrvtests/tests/tickets/ticket49658_test.py
new file mode 100644
index 0000000..53522df
--- /dev/null
+++ b/dirsrvtests/tests/tickets/ticket49658_test.py
@@ -0,0 +1,4264 @@
+import logging
+import pytest
+import os
+import ldap
+import time
+import sys
+print(sys.path)
+from lib389 import Entry
+from lib389._constants import DEFAULT_SUFFIX
+from lib389.idm.user import UserAccounts, TEST_USER_PROPERTIES
+from lib389.topologies import topology_m3 as topo
+
+DEBUGGING = os.getenv("DEBUGGING", default=False)
+if DEBUGGING:
+ logging.getLogger(__name__).setLevel(logging.DEBUG)
+else:
+ logging.getLogger(__name__).setLevel(logging.INFO)
+log = logging.getLogger(__name__)
+
+
+MAX_EMPLOYEENUMBER_USER = 20
+MAX_STANDARD_USER = 100
+MAX_USER = MAX_STANDARD_USER + MAX_EMPLOYEENUMBER_USER
+EMPLOYEENUMBER_RDN_START = 0
+
+USER_UID='user_'
+BASE_DISTINGUISHED = 'ou=distinguished,ou=people,%s' % (DEFAULT_SUFFIX)
+BASE_REGULAR = 'ou=regular,ou=people,%s' % (DEFAULT_SUFFIX)
+
+def _user_get_dn(no):
+ uid = '%s%d' % (USER_UID, no)
+ dn = 'uid=%s,%s' % (uid, BASE_REGULAR)
+ return (uid, dn)
+
+def add_user(server, no, init_val):
+ (uid, dn) = _user_get_dn(no)
+ log.fatal('Adding user (%s): ' % dn)
+ server.add_s(Entry((dn, {'objectclass': ['top', 'person', 'organizationalPerson', 'inetOrgPerson'],
+ 'uid': [uid],
+ 'sn' : [uid],
+ 'cn' : [uid],
+ 'employeeNumber': init_val})))
+ return dn
+
+def _employeenumber_user_get_dn(no):
+ employeeNumber = str(no)
+ dn = 'employeeNumber=%s,%s' % (employeeNumber, BASE_DISTINGUISHED)
+ return (employeeNumber, dn)
+
+def add_employeenumber_user(server, no):
+ (uid, dn) = _employeenumber_user_get_dn(EMPLOYEENUMBER_RDN_START + no)
+ log.fatal('Adding user (%s): ' % dn)
+ server.add_s(Entry((dn, {'objectclass': ['top', 'person', 'organizationalPerson', 'inetOrgPerson'],
+ 'uid': [uid],
+ 'sn' : [uid],
+ 'cn' : [uid],
+ 'employeeNumber': str(EMPLOYEENUMBER_RDN_START + no)})))
+ return dn
+
+def save_stuff():
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_11 = '11'.encode()
+ value_1000 = '1000'.encode()
+ value_13 = '13'.encode()
+ value_14 = '14'.encode()
+
+ # Step 2
+ test_user_dn= add_user(M3, 0, value_11)
+ log.info('Adding %s on M3' % test_user_dn)
+ M3.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_11), (ldap.MOD_ADD, 'employeeNumber', value_1000)])
+ ents = M3.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == 1
+
+
+ # Step 3
+ # Check the entry is replicated on M1
+ for j in range(30):
+ try:
+ ent = M1.getEntry(test_user_dn, ldap.SCOPE_BASE,)
+ if not ent.hasAttr('employeeNumber'):
+ # wait for the MOD
+ log.info('M1 waiting for employeeNumber')
+ time.sleep(1)
+ continue;
+ break;
+ except ldap.NO_SUCH_OBJECT:
+ time.sleep(1)
+ pass
+ time.sleep(1)
+ ents = M1.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == 1
+
+ # Check the entry is replicated on M2
+ for j in range(30):
+ try:
+ ent = M2.getEntry(test_user_dn, ldap.SCOPE_BASE,)
+ if not ent.hasAttr('employeeNumber'):
+ # wait for the MOD
+ log.info('M2 waiting for employeeNumber')
+ time.sleep(1)
+ continue;
+
+ break;
+ except ldap.NO_SUCH_OBJECT:
+ time.sleep(1)
+ pass
+ time.sleep(1)
+ ents = M2.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == 1
+
+def test_ticket49658_init(topo):
+ """Specify a test case purpose or name here
+
+ :id: 0
+ :setup: 3 Master Instances
+ :steps:
+ 1. Create 3 suppliers
+ 2. Create on M3 MAX_USER test entries having a single-value attribute employeeNumber=11
+ and update it MOD_DEL 11 + MOD_ADD 1000
+ 3. Check they are replicated on M1 and M2
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_11 = '11'.encode()
+ value_1000 = '1000'.encode()
+
+ # Step 2
+ M3.add_s(Entry((BASE_DISTINGUISHED, {'objectclass': ['top', 'organizationalUnit'],
+ 'ou': ['distinguished']})))
+ for i in range(MAX_EMPLOYEENUMBER_USER):
+ test_user_dn= add_employeenumber_user(M3, i)
+ log.info('Adding %s on M3' % test_user_dn)
+ ents = M3.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == (i + 1)
+
+ M3.add_s(Entry((BASE_REGULAR, {'objectclass': ['top', 'organizationalUnit'],
+ 'ou': ['regular']})))
+ for i in range(MAX_STANDARD_USER):
+ test_user_dn= add_user(M3, i, value_11)
+ log.info('Adding %s on M3' % test_user_dn)
+ M3.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_11), (ldap.MOD_ADD, 'employeeNumber', value_1000)])
+ ents = M3.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == (MAX_EMPLOYEENUMBER_USER + i + 1)
+
+
+ # Step 3
+ # Check the last entry is replicated on M1
+ (uid, test_user_dn) = _user_get_dn(MAX_STANDARD_USER - 1)
+ for j in range(30):
+ try:
+ ent = M1.getEntry(test_user_dn, ldap.SCOPE_BASE,)
+ if not ent.hasAttr('employeeNumber'):
+ # wait for the MOD
+ log.info('M1 waiting for employeeNumber')
+ time.sleep(1)
+ continue;
+ break;
+ except ldap.NO_SUCH_OBJECT:
+ time.sleep(1)
+ pass
+ time.sleep(1)
+ ents = M1.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_USER
+
+ # Check the last entry is replicated on M2
+ for j in range(30):
+ try:
+ ent = M2.getEntry(test_user_dn, ldap.SCOPE_BASE,)
+ if not ent.hasAttr('employeeNumber'):
+ # wait for the MOD
+ log.info('M2 waiting for employeeNumber')
+ time.sleep(1)
+ continue;
+
+ break;
+ except ldap.NO_SUCH_OBJECT:
+ time.sleep(1)
+ pass
+ time.sleep(1)
+ ents = M2.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_USER
+
+def test_ticket49658_0(topo):
+ """Do MOD(DEL+ADD) and replicate MOST RECENT first
+ M1: MOD(DEL+ADD) -> V1
+ M2: MOD(DEL+ADD) -> V1
+ expected: V1
+
+ :id: 0
+ :setup: 3 Master Instances
+ 1. using user_0 where employNumber=1000
+ :steps:
+ 1. Create 3 suppliers
+ 2. Isolate M1 and M2 by pausing the replication agreements
+ 3. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 4. On M2 do MOD_DEL 1000 + MOD_ADD_13
+ 5. Enable replication agreement M2 -> M3, so that update step 6 is replicated first
+ 6. Enable replication agreement M1 -> M3, so that update step 5 is replicated second
+ 7. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'.encode()
+ last = '0'
+ value_end = last.encode()
+ theFilter = '(employeeNumber=%s)' % last
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 2
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 3
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ M1.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_1000), (ldap.MOD_ADD, 'employeeNumber', value_end)])
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 4
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M2.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_1000), (ldap.MOD_ADD, 'employeeNumber', value_end)])
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+def test_ticket49658_1(topo):
+ """Do MOD(DEL+ADD) and replicate OLDEST first
+ M2: MOD(DEL+ADD) -> V1
+ M1: MOD(DEL+ADD) -> V1
+ expected: V1
+
+ :id: 1
+ :setup: 3 Master Instances
+ 1. using user_1 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M2 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'.encode()
+ last = '1'
+ value_end = last.encode()
+ theFilter = '(employeeNumber=%s)' % last
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(1))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M2.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_1000), (ldap.MOD_ADD, 'employeeNumber', value_end)])
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M1.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_1000), (ldap.MOD_ADD, 'employeeNumber', value_end)])
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+def test_ticket49658_2(topo):
+ """Do MOD(ADD+DEL) and replicate OLDEST first
+ M2: MOD(ADD+DEL) -> V1
+ M1: MOD(ADD+DEL) -> V1
+ expected: V1
+
+ :id: 2
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M2 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'.encode()
+ last = '2'
+ value_end = last.encode()
+ theFilter = '(employeeNumber=%s)' % last
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M2.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end),(ldap.MOD_DELETE, 'employeeNumber', value_1000)])
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M1.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end), (ldap.MOD_DELETE, 'employeeNumber', value_1000)])
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+def test_ticket49658_3(topo):
+ """Do MOD(ADD+DEL) and replicate MOST RECENT first
+ M1: MOD(ADD+DEL) -> V1
+ M2: MOD(ADD+DEL) -> V1
+ expected: V1
+ :id: 3
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_DEL 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'.encode()
+ last = '3'
+ value_end = last.encode()
+ theFilter = '(employeeNumber=%s)' % last
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ M1.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end),(ldap.MOD_DELETE, 'employeeNumber', value_1000)])
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M2.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end), (ldap.MOD_DELETE, 'employeeNumber', value_1000)])
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+def test_ticket49658_4(topo):
+ """Do MOD(ADD+DEL) MOD(REPL) and replicate MOST RECENT first
+ M1: MOD(ADD+DEL) -> V1
+ M2: MOD(REPL) -> V1
+ expected: V1
+
+ :id: 4
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'.encode()
+ last = '4'
+ value_end = last.encode()
+ theFilter = '(employeeNumber=%s)' % last
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ M1.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end),(ldap.MOD_DELETE, 'employeeNumber', value_1000)])
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M2.modify_s(test_user_dn, [(ldap.MOD_REPLACE, 'employeeNumber', value_end)])
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+def test_ticket49658_5(topo):
+ """Do MOD(REPL) MOD(ADD+DEL) and replicate MOST RECENT first
+ M1: MOD(REPL) -> V1
+ M2: MOD(ADD+DEL) -> V1
+ expected: V1
+ :id: 5
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'.encode()
+ last = '5'
+ value_end = last.encode()
+ theFilter = '(employeeNumber=%s)' % last
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ M1.modify_s(test_user_dn, [(ldap.MOD_REPLACE, 'employeeNumber', value_end)])
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M2.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end),(ldap.MOD_DELETE, 'employeeNumber', value_1000)])
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+def test_ticket49658_6(topo):
+ """Do
+ M1: MOD(REPL) -> V1
+ M2: MOD(ADD+DEL) -> V2
+ expected: V2
+
+ :id: 6
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '6'
+ value_S1 = '6.1'
+ value_S2 = '6.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_ADD, 'employeeNumber', value_S2.encode()),(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode())],
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_7(topo):
+ """Do
+ M1: MOD(ADD+DEL) -> V1
+ M2: MOD(REPL) -> V2
+ expected: V2
+
+ :id: 7
+ :setup: 3 Master Instances
+ :steps:
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '7'
+ value_S1 = '7.1'
+ value_S2 = '7.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_ADD, 'employeeNumber', value_S1.encode()),(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_8(topo):
+ """Do
+ M1: MOD(DEL+ADD) -> V1
+ M2: MOD(REPL) -> V2
+ expected: V2
+
+ :id: 8
+ :setup: 3 Master Instances
+ :steps:
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '8'
+ value_S1 = '8.1'
+ value_S2 = '8.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+def test_ticket49658_9(topo):
+ """Do
+ M1: MOD(REPL) -> V1
+ M2: MOD(DEL+ADD) -> V2
+ expected: V2
+
+ :id: 9
+ :setup: 3 Master Instances
+ :steps:
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '9'
+ value_S1 = '9.1'
+ value_S2 = '9.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+
+def test_ticket49658_10(topo):
+ """Do
+ M1: MOD(REPL) -> V1
+ M2: MOD(REPL) -> V2
+ expected: V2
+
+ :id: 10
+ :setup: 3 Master Instances
+ :steps:
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '10'
+ value_S1 = '10.1'
+ value_S2 = '10.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+
+def test_ticket49658_11(topo):
+ """Do
+ M2: MOD(REPL) -> V2
+ M1: MOD(REPL) -> V1
+ expected: V1
+
+ :id: 11
+ :setup: 3 Master Instances
+ :steps:
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '11'
+ value_S1 = '11.1'
+ value_S2 = '11.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_12(topo):
+ """Do
+ M2: MOD(ADD+DEL) -> V2
+ M1: MOD(REPL) -> V1
+ expected: V1
+
+ :id: 12
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '12'
+ value_S1 = '12.1'
+ value_S2 = '12.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_ADD, 'employeeNumber', value_S2.encode()),(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode())],
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_13(topo):
+ """Do
+ M2: MOD(DEL+ADD) -> V2
+ M1: MOD(REPL) -> V1
+ expected: V1
+
+ :id: 13
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '13'
+ value_S1 = '13.1'
+ value_S2 = '13.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+def test_ticket49658_14(topo):
+ """Do
+ M2: MOD(DEL+ADD) -> V2
+ M1: MOD(DEL+ADD) -> V1
+ expected: V1
+
+ :id: 14
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '14'
+ value_S1 = '14.1'
+ value_S2 = '14.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_15(topo):
+ """Do
+ M2: MOD(ADD+DEL) -> V2
+ M1: MOD(DEL+ADD) -> V1
+ expected: V1
+
+ :id: 15
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '15'
+ value_S1 = '15.1'
+ value_S2 = '15.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_ADD, 'employeeNumber', value_S2.encode()),(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode())],
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+def _resume_ra_M1_then_M2(M1, M2, M3):
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ time.sleep(4)
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+ time.sleep(4)
+
+def _resume_ra_M2_then_M1(M1, M2, M3):
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+ time.sleep(4)
+
+
+def test_ticket49658_16(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V1
+ expected: V1
+ resume order: M2, M1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '1'
+ last = '1'
+ value_S1 = '1.1'
+ value_S2 = value_S1
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S2_MODRDN": value_S2,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+def test_ticket49658_17(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ expected: V2
+ resume order: M2 then M1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '2'
+ last = '2'
+ value_S1 = '2.1'
+ value_S2 = '2.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_18(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ expected: V2
+ resume order: M1 then M2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '2'
+ last = '3'
+ value_S1 = '3.1'
+ value_S2 = '3.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_19(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ Replicate order: M2 then M1
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '3'
+ last = '4'
+ value_S1 = '4.1'
+ value_S2 = '4.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_20(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ Replicate order: M1 then M2
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '3'
+ last = '5'
+ value_S1 = '5.1'
+ value_S2 = '5.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_21(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(DEL/ADD) -> V1
+ Replicate order: M2 then M1
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '3'
+ last = '6'
+ value_S1 = '6.1'
+ value_S2 = '6.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_22(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(DEL/ADD) -> V1
+ Replicate: M1 then M2
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '3'
+ last = '7'
+ value_S1 = '7.1'
+ value_S2 = '7.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_23(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MOD(REPL) -> V2
+ Replicate order: M2 then M1
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '8'
+ value_S1 = '8.1'
+ value_S2 = '8.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_24(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MOD(REPL) -> V2
+ Replicate order: M1 then M2
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '9'
+ value_S1 = '9.1'
+ value_S2 = '9.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_25(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MOD(DEL/ADD) -> V2
+ Replicate order: M1 then M2
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '10'
+ value_S1 = '10.1'
+ value_S2 = '10.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S2.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_26(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MOD(DEL/ADD) -> V2
+ Replicate order: M2 then M1
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '11'
+ value_S1 = '11.1'
+ value_S2 = '11.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S2.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_27(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(DEL/ADD) -> V1
+ M2: MOD(REPL) -> V2
+ Replicate order: M1 then M2
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '12'
+ value_S1 = '12.1'
+ value_S2 = '12.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_28(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(DEL/ADD) -> V1
+ M2: MOD(REPL) -> V2
+ Replicate order: M2 then M1
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '13'
+ value_S1 = '13.1'
+ value_S2 = '13.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+def test_ticket49658_29(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(DEL/ADD) -> V1
+ M2: MOD(DEL/ADD) -> V2
+ Replicate order: M1 then M2
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '14'
+ value_S1 = '14.1'
+ value_S2 = '14.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S2.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_30(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(DEL/ADD) -> V1
+ M2: MOD(DEL/ADD) -> V2
+ Replicate order: M2 then M1
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '15'
+ value_S1 = '15.1'
+ value_S2 = '15.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S2.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_31(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MOD(REPL) -> V2
+ M2: MODRDN -> V1
+ Replicate order: M2 then M1
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '16'
+ value_S1 = '16.1'
+ value_S2 = '16.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN_1": value_S2,
+ "S2_MODRDN_2": value_S1,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_1"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_1"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN_1"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ description["S2"].rename_s(new_test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_2"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_2"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+def test_ticket49658_32(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MOD(REPL) -> V2
+ M2: MODRDN -> V1
+ Replicate order: M1 then M2
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '17'
+ value_S1 = '17.1'
+ value_S2 = '17.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN_1": value_S2,
+ "S2_MODRDN_2": value_S1,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_1"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_1"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN_1"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ description["S2"].rename_s(new_test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_2"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_2"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_33(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MODRDN -> V1
+ Replicate order: M2 then M1
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '18'
+ value_S1 = '18.1'
+ value_S2 = '18.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MODRDN_1": value_S2,
+ "S2_MODRDN_2": value_S1,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_1"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_1"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN_1"])
+ description["S2"].rename_s(new_test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_2"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_2"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_34(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MODRDN -> V1
+ Replicate order: M1 then M2
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '19'
+ value_S1 = '19.1'
+ value_S2 = '19.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MODRDN_1": value_S2,
+ "S2_MODRDN_2": value_S1,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_1"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_1"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN_1"])
+ description["S2"].rename_s(new_test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_2"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_2"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+if __name__ == '__main__':
+ # Run isolated
+ # -s for DEBUG mode
+ CURRENT_FILE = os.path.realpath(__file__)
+ pytest.main(["-s", CURRENT_FILE])
+
diff --git a/ldap/servers/slapd/entrywsi.c b/ldap/servers/slapd/entrywsi.c
index 58f7870..080eb15 100644
--- a/ldap/servers/slapd/entrywsi.c
+++ b/ldap/servers/slapd/entrywsi.c
@@ -359,6 +359,13 @@ entry_add_present_attribute_wsi(Slapi_Entry *e, Slapi_Attr *a)
* Preserves LDAP Information Model constraints,
* returning an LDAP result code.
*/
+static void entry_dump_stateinfo(char *msg, Slapi_Entry* e);
+static Slapi_Value *attr_most_recent_deleted_value(Slapi_Attr *a);
+static void resolve_single_valued_two_values(Slapi_Entry *e, Slapi_Attr *a, int attribute_state, Slapi_Value *current_value, Slapi_Value *second_current_value);
+static void resolve_single_valued_check_restore_deleted_value(Slapi_Entry *e, Slapi_Attr *a);
+static void resolve_single_valued_zap_current(Slapi_Entry *e, Slapi_Attr *a);
+static void resolve_single_valued_set_adcsn(Slapi_Attr *a);
+static void resolve_single_valued_zap_deleted(Slapi_Attr *a);
static void resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribute_state);
static void resolve_attribute_state_deleted_to_present(Slapi_Entry *e, Slapi_Attr *a, Slapi_Value **valuestoupdate);
static void resolve_attribute_state_present_to_deleted(Slapi_Entry *e, Slapi_Attr *a, Slapi_Value **valuestoupdate);
@@ -387,6 +394,20 @@ entry_add_present_values_wsi(Slapi_Entry *e, const char *type, struct berval **b
return retVal;
}
+/* Used for debug purpose, it dumps into the error log the
+ * entry with the replication stateinfo
+ */
+static void
+entry_dump_stateinfo(char *msg, Slapi_Entry* e)
+{
+ char *s;
+ int32_t len = 0;
+
+ s = slapi_entry2str_with_options(e, &len, SLAPI_DUMP_STATEINFO);
+ slapi_log_err(SLAPI_LOG_ERR, msg, "%s\n", s);
+ slapi_ch_free((void **)&s);
+}
+
static int
entry_add_present_values_wsi_single_valued(Slapi_Entry *e, const char *type, struct berval **bervals, const CSN *csn, int urp, long flags)
{
@@ -705,6 +726,10 @@ entry_delete_present_values_wsi_single_valued(Slapi_Entry *e, const char *type,
/* The attribute is single valued and the value was successful deleted */
/* but there could have been an add in the same operation, so double check */
if (valueset_isempty(&a->a_present_values)) {
+ /* A doubt here, a direct update deletes the last value
+ * of a single valued attribute. It will only contain deleted values.
+ * Why not setting the adcsn (attr_set_deletion_csn) ?
+ */
entry_present_attribute_to_deleted_attribute(e, a);
}
} else if (retVal != LDAP_SUCCESS) {
@@ -1229,169 +1254,254 @@ resolve_attribute_state_present_to_deleted(Slapi_Entry *e, Slapi_Attr *a, Slapi_
}
}
-static void
-resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribute_state)
+/* Retrieve from the deleted values the one that
+ * was the most recently deleted. Based on its vdcsn
+ */
+static Slapi_Value *
+attr_most_recent_deleted_value(Slapi_Attr *a)
{
- Slapi_Value *current_value = NULL;
- Slapi_Value *pending_value = NULL;
- Slapi_Value *new_value = NULL;
- const CSN *current_value_vucsn;
- const CSN *pending_value_vucsn;
- const CSN *pending_value_vdcsn;
- const CSN *adcsn;
+ Slapi_Value *v, *most_recent_v;
int i;
+ CSN *vdcsn, *most_recent_vdcsn;
- /*
- * this call makes sure that the attribute does not have a pending_value
- * or deletion_csn which is before the current_value.
- */
- i = slapi_attr_first_value(a, ¤t_value);
- if (i != -1) {
- slapi_attr_next_value(a, i, &new_value);
- }
- attr_first_deleted_value(a, &pending_value);
- /* purge_attribute_state_single_valued */
- adcsn = attr_get_deletion_csn(a);
- current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
- pending_value_vucsn = value_get_csn(pending_value, CSN_TYPE_VALUE_UPDATED);
- pending_value_vdcsn = value_get_csn(pending_value, CSN_TYPE_VALUE_DELETED);
- if ((pending_value != NULL && (csn_compare(adcsn, pending_value_vucsn) < 0)) ||
- (pending_value == NULL && (csn_compare(adcsn, current_value_vucsn) < 0))) {
- attr_set_deletion_csn(a, NULL);
- adcsn = NULL;
+ vdcsn = NULL;
+ most_recent_vdcsn = NULL;
+ i = attr_first_deleted_value(a, &v);
+ most_recent_v = v;
+
+ while (i != -1) {
+ vdcsn = value_get_csn(v, CSN_TYPE_VALUE_DELETED);
+
+ if (csn_compare((const CSN *)most_recent_vdcsn, (const CSN *)vdcsn) < 0) {
+ most_recent_v = v;
+ most_recent_vdcsn = vdcsn;
+ }
+ i = attr_next_deleted_value(a, i, &v);
}
+ return most_recent_v;
+}
- /* in the case of the following:
- * add: value2
- * delete: value1
- * we will have current_value with VUCSN CSN1
- * and pending_value with VDCSN CSN2
- * and new_value == NULL
- * current_value != pending_value
- * and
- * VUCSN == VDCSN (ignoring subseq)
- * even though value1.VDCSN > value2.VUCSN
- * value2 should still win because the value is _different_
- */
- if (current_value && pending_value && !new_value && !adcsn &&
- (0 != slapi_value_compare(a, current_value, pending_value)) &&
- (0 == csn_compare_ext(current_value_vucsn, pending_value_vdcsn, CSN_COMPARE_SKIP_SUBSEQ))) {
- /* just remove the deleted value */
- entry_deleted_value_to_zapped_value(a, pending_value);
- pending_value = NULL;
- } else if (current_value && pending_value && !new_value && adcsn &&
- (attribute_state == ATTRIBUTE_DELETED) &&
- current_value_vucsn && !pending_value_vucsn && pending_value_vdcsn &&
- (csn_compare(current_value_vucsn, pending_value_vdcsn) > 0) &&
- (csn_compare(adcsn, pending_value_vdcsn) == 0)) {
- /* in the case of the following:
- * beginning attr state is a deleted value
- * incoming operation is
- * add: newvalue
- * attribute_state is ATTRIBUTE_DELETED
- * so we have both a current_value and a pending_value
- * new_value is NULL
- * current_value_vucsn is CSN1
- * pending_value_vucsn is NULL
- * pending_value_vdcsn is CSN2
- * adcsn is CSN2 == pending_value_vdcsn
- * CSN1 > CSN2
- * since the pending_value is deleted, and the current_value has
- * a greater CSN, we should keep the current_value and zap
- * the pending_value
+/* This routine applies for single valued attribute.
+ * The attribute has two current values, it keeps the most recent one
+ * and zap the oldest
+ */
+static void
+resolve_single_valued_two_values(Slapi_Entry *e, Slapi_Attr *a, int attribute_state, Slapi_Value *current_value, Slapi_Value *second_current_value)
+{
+
+ CSN *current_value_vucsn;
+ CSN *second_current_value_vucsn;
+ Slapi_Value *value_to_zap;
+
+ current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
+ second_current_value_vucsn = value_get_csn(second_current_value, CSN_TYPE_VALUE_UPDATED);
+
+ /* First determine which present value will be zapped */
+ if (csn_compare((const CSN *)second_current_value_vucsn, (const CSN *)current_value_vucsn) < 0) {
+ /*
+ * The second value is older but was distinguished at the time the current value was added
+ * then the second value should become current
*/
- /* just remove the deleted value */
- entry_deleted_value_to_zapped_value(a, pending_value);
- /* move the attribute to the present attributes list */
- entry_deleted_attribute_to_present_attribute(e, a);
- pending_value = NULL;
- attr_set_deletion_csn(a, NULL);
- return; /* we are done - we are keeping the present value */
- } else if (new_value == NULL) {
- /* check if the pending value should become the current value */
- if (pending_value != NULL) {
- if (!value_distinguished_at_csn(e, a, current_value, pending_value_vucsn)) {
- /* attribute.current_value = attribute.pending_value; */
- /* attribute.pending_value = NULL; */
- entry_present_value_to_zapped_value(a, current_value);
- entry_deleted_value_to_present_value(a, pending_value);
- current_value = pending_value;
- pending_value = NULL;
- current_value_vucsn = pending_value_vucsn;
- pending_value_vucsn = NULL;
- }
+ if (value_distinguished_at_csn(e, a, second_current_value, (const CSN *)current_value_vucsn)) {
+ value_to_zap = current_value;
+ } else {
+ /* The second value being not distinguished, zap it as it is a single valued attribute */
+ value_to_zap = second_current_value;
}
- /* check if the current value should be deleted */
- if (current_value != NULL) {
- if (csn_compare(adcsn, current_value_vucsn) > 0) /* check if the attribute was deleted after the value was last updated */
- {
- if (!value_distinguished_at_csn(e, a, current_value, current_value_vucsn)) {
- entry_present_value_to_zapped_value(a, current_value);
- current_value = NULL;
- current_value_vucsn = NULL;
- }
- }
+
+ } else {
+ /* Here the current_value is older than the second_current_value */
+ if (value_distinguished_at_csn(e, a, current_value, (const CSN *)second_current_value_vucsn)) {
+ /* current_value was distinguished at the time the second value was added
+ * then the current_value should become the current */
+ value_to_zap = second_current_value;
+ } else {
+ value_to_zap = current_value;
}
- } else /* addition of a new value */
- {
- const CSN *new_value_vucsn = value_get_csn(new_value, CSN_TYPE_VALUE_UPDATED);
- if (csn_compare(new_value_vucsn, current_value_vucsn) < 0) {
- /*
- * if the new value was distinguished at the time the current value was added
- * then the new value should become current
+ }
+ entry_present_value_to_zapped_value(a, value_to_zap);
+
+
+
+}
+
+/* This routine applies for single valued attribute.
+ * It checks if the deleted value is more recent than
+ * the present one. If it is, it resurect the deleted value
+ *
+ * This function leaves untouch the adcsn
+ */
+static void
+resolve_single_valued_check_restore_deleted_value(Slapi_Entry *e, Slapi_Attr *a)
+{
+ Slapi_Value *deleted_value = NULL;
+ Slapi_Value *current_value = NULL;
+
+ /* Retrieve the deleted and current value */
+ deleted_value = attr_most_recent_deleted_value(a);
+ if (deleted_value == NULL) {
+ return;
+ }
+ slapi_attr_first_value(a, ¤t_value);
+
+ if (current_value == NULL) {
+ /* An attribute needs a present value */
+ entry_deleted_value_to_present_value(a, deleted_value);
+ } else {
+ CSN *current_value_vucsn;
+ CSN *deleted_value_vucsn;
+ CSN *deleted_value_vdcsn;
+
+ deleted_value_vucsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_UPDATED);
+ deleted_value_vdcsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_DELETED);
+ current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
+ if (deleted_value_vucsn &&
+ !value_distinguished_at_csn(e, a, current_value, (const CSN *)deleted_value_vucsn) &&
+ (csn_compare((const CSN *)current_value_vucsn, (const CSN *)deleted_value_vucsn) < 0) &&
+ (csn_compare((const CSN *)deleted_value_vdcsn, (const CSN *)current_value_vucsn) < 0)) {
+ /* the condition to resurrect the deleted value is
+ * - it is more recent than the current value
+ * - its value was deleted before the current value
+ * - the current value is not distinguished
*/
- if (value_distinguished_at_csn(e, a, new_value, current_value_vucsn)) {
- /* attribute.pending_value = attribute.current_value */
- /* attribute.current_value = new_value */
- if (pending_value == NULL) {
- entry_present_value_to_deleted_value(a, current_value);
- } else {
- entry_present_value_to_zapped_value(a, current_value);
- }
- pending_value = current_value;
- current_value = new_value;
- new_value = NULL;
- pending_value_vucsn = current_value_vucsn;
- current_value_vucsn = new_value_vucsn;
- } else {
- /* new_value= NULL */
- entry_present_value_to_zapped_value(a, new_value);
- new_value = NULL;
- }
- } else /* new value is after the current value */
- {
- if (!value_distinguished_at_csn(e, a, current_value, new_value_vucsn)) {
- /* attribute.current_value = new_value */
- entry_present_value_to_zapped_value(a, current_value);
- current_value = new_value;
- new_value = NULL;
- current_value_vucsn = new_value_vucsn;
- } else /* value is distinguished - check if we should replace the current pending value */
- {
- if (csn_compare(new_value_vucsn, pending_value_vucsn) > 0) {
- /* attribute.pending_value = new_value */
- entry_deleted_value_to_zapped_value(a, pending_value);
- entry_present_value_to_deleted_value(a, new_value);
- pending_value = new_value;
- new_value = NULL;
- pending_value_vucsn = new_value_vucsn;
- }
- }
+ entry_present_value_to_zapped_value(a, current_value);
+ entry_deleted_value_to_present_value(a, deleted_value);
}
}
+}
+/* This function deals with single valued attribute
+ * It zap the current value if the adcsn is more recent and the value is not distinguished
+ */
+static void
+resolve_single_valued_zap_current(Slapi_Entry *e, Slapi_Attr *a)
+{
+ Slapi_Value *current_value = NULL;
+ CSN *current_value_vucsn;
+ CSN *adcsn;
- /*
- * This call ensures that the attribute does not have a pending_value
- * or a deletion_csn that is earlier than the current_value.
+ /* check if the current value should be deleted because
+ * older than adcsn and not distinguished
*/
- /* purge_attribute_state_single_valued */
- if ((pending_value != NULL && (csn_compare(adcsn, pending_value_vucsn) < 0)) ||
- (pending_value == NULL && (csn_compare(adcsn, current_value_vucsn) < 0))) {
+ slapi_attr_first_value(a, ¤t_value);
+ current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
+ adcsn = attr_get_deletion_csn(a);
+ if (current_value != NULL) {
+ if (csn_compare((const CSN *)adcsn, (const CSN *) current_value_vucsn) > 0) {
+ /* the attribute was deleted after the value was last updated */
+ if (!value_distinguished_at_csn(e, a, current_value, (const CSN *) current_value_vucsn)) {
+ entry_present_value_to_zapped_value(a, current_value);
+ }
+ }
+ }
+}
+/* This function deals with single valued attribute
+ * It reset the adcsn if
+ * - there is no deleted value and current value is more recent than the adcsn
+ * - there is a deleted value and it is more recent than the adcsn
+ */
+static void
+resolve_single_valued_set_adcsn(Slapi_Attr *a)
+{
+ Slapi_Value *deleted_value = NULL;
+ Slapi_Value *current_value = NULL;
+ CSN *current_value_vucsn;
+ CSN *deleted_value_vucsn;
+ CSN *adcsn;
+
+ slapi_attr_first_value(a, ¤t_value);
+ current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
+ deleted_value = attr_most_recent_deleted_value(a);
+ deleted_value_vucsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_UPDATED);
+ adcsn = attr_get_deletion_csn(a);
+ if ((deleted_value != NULL && (csn_compare(adcsn, (const CSN *) deleted_value_vucsn) < 0)) ||
+ (deleted_value == NULL && (csn_compare(adcsn, (const CSN *) current_value_vucsn) < 0))) {
attr_set_deletion_csn(a, NULL);
- adcsn = NULL;
}
+}
+/* This function deals with single valued attribute
+ * It checks if the deleted value worth to be kept
+ *
+ * deleted value is zapped if
+ * - it is the result of MOD_REPL that is older than current value
+ * - It is the result of MOD_DEL_<value> that is belong to the same operation that set the current value
+ */
+static void
+resolve_single_valued_zap_deleted(Slapi_Attr *a)
+{
+ Slapi_Value *deleted_value = NULL;
+ Slapi_Value *current_value = NULL;
+ CSN *current_value_vucsn;
+ CSN *deleted_value_vucsn;
+ CSN *deleted_value_vdcsn;
+ CSN *deleted_value_csn;
+ PRBool deleted_on_mod_del = PR_FALSE; /* flag if a value was deleted specifically */
+
+ /* Now determine if the deleted value worth to be kept */
+ slapi_attr_first_value(a, ¤t_value);
+ current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
+
+ deleted_value = attr_most_recent_deleted_value(a);
+ deleted_value_vucsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_UPDATED);
+ deleted_value_vdcsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_DELETED);
+
+ /* get the appropriate csn to take into consideration: either from MOD_REPL or from MOD_DEL_specific */
+ if (csn_compare((const CSN *) deleted_value_vdcsn, (const CSN *) deleted_value_vucsn) <= 0) {
+ deleted_value_csn = deleted_value_vucsn;
+ } else {
+ deleted_value_csn = deleted_value_vdcsn;
+ if (0 == csn_compare_ext((const CSN *) current_value_vucsn, (const CSN *) deleted_value_vdcsn, CSN_COMPARE_SKIP_SUBSEQ)) {
+ /* the deleted value was specifically delete in the same operation that set the current value */
+ deleted_on_mod_del = PR_TRUE;
+ }
+ }
+ if ((csn_compare((const CSN *) deleted_value_csn, (const CSN *) current_value_vucsn) < 0) || deleted_on_mod_del) {
+ entry_deleted_value_to_zapped_value(a, deleted_value);
+ }
+}
+
+/* This function deals with single valued attribute
+ * It does a set of cleanup in the current/deleted values in order
+ * to conform the schema, take care of distinguished values and only preserve the
+ * values that worth to be kept.
+ */
+static void
+resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribute_state)
+{
+ int32_t nbval, i;
+ Slapi_Value *current_value = NULL;
+
+ /* retrieve the current value(s) */
+ slapi_attr_get_numvalues(a, &nbval);
+ i = slapi_attr_first_value(a, ¤t_value);
+
+ /* If there are several values, first determine which value will be the current (present) one */
+ if (nbval > 1) {
+ /* There are several values for a single valued attribute, keep the most recent one */
+ if (i == -1) {
+ slapi_log_err(SLAPI_LOG_ERR, "resolve_attribute_state_single_valued", "Unexpected state of %s that contains more than one value but can not read the second\n", a->a_type);
+ } else {
+ Slapi_Value *second_current_value = NULL;
+
+ slapi_attr_next_value(a, i, &second_current_value);
+ resolve_single_valued_two_values(e, a, attribute_state, current_value, second_current_value);
+ }
+ }
+ /* There is only one current value (present value) */
+
+ /* Now determine if the deleted value needs to replace the current value */
+ resolve_single_valued_check_restore_deleted_value(e, a);
+
+ /* Now determine if the deleted value worth to be kept (vs. current value) */
+ resolve_single_valued_zap_deleted(a);
+
+ /* Now determine if the current value worth to be kept (vs. adcsn) */
+ resolve_single_valued_zap_current(e, a);
+
+ /* Now set the adcsn */
+ resolve_single_valued_set_adcsn(a);
- /* set attribute state */
+ /* set the attribute in the correct list in the entry: present or deleted */
+ slapi_attr_first_value(a, ¤t_value);
if (current_value == NULL) {
if (attribute_state == ATTRIBUTE_PRESENT) {
entry_present_attribute_to_deleted_attribute(e, a);
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years, 2 months
[389-ds-base] branch 389-ds-base-1.3.8 updated: Ticket 49658 - In replicated topology a single-valued attribute can diverge
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
tbordaz pushed a commit to branch 389-ds-base-1.3.8
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.3.8 by this push:
new 81ce57b Ticket 49658 - In replicated topology a single-valued attribute can diverge
81ce57b is described below
commit 81ce57b87eed3870822ae71eceb1292bca836bb5
Author: Thierry Bordaz <tbordaz(a)redhat.com>
AuthorDate: Tue May 15 16:45:56 2018 +0200
Ticket 49658 - In replicated topology a single-valued attribute can diverge
Bug Description:
When deleting a specific value of a single valued attribute,
the deleted value can be erronously resurrected.
Fix Description:
This second fix is a rewrite of entry state resolution.
The original function (resolve_attribute_state_single_valued) implemented
a main algorythm but it was heavily merged with resolution of specific cases.
It was too difficult to make the function understandable and preserving
the handling of the specific cases.
The risk of that rewrite fix is that I can not guarantee it fully covers
the set of specific cases
https://pagure.io/389-ds-base/issue/49658
Reviewed by: William Brown (Thanks !!)
Platforms tested: F27
Flag Day: no
Doc impact: no
---
dirsrvtests/tests/tickets/ticket49658_test.py | 4264 +++++++++++++++++++++++++
ldap/servers/slapd/entrywsi.c | 404 ++-
2 files changed, 4521 insertions(+), 147 deletions(-)
diff --git a/dirsrvtests/tests/tickets/ticket49658_test.py b/dirsrvtests/tests/tickets/ticket49658_test.py
new file mode 100644
index 0000000..53522df
--- /dev/null
+++ b/dirsrvtests/tests/tickets/ticket49658_test.py
@@ -0,0 +1,4264 @@
+import logging
+import pytest
+import os
+import ldap
+import time
+import sys
+print(sys.path)
+from lib389 import Entry
+from lib389._constants import DEFAULT_SUFFIX
+from lib389.idm.user import UserAccounts, TEST_USER_PROPERTIES
+from lib389.topologies import topology_m3 as topo
+
+DEBUGGING = os.getenv("DEBUGGING", default=False)
+if DEBUGGING:
+ logging.getLogger(__name__).setLevel(logging.DEBUG)
+else:
+ logging.getLogger(__name__).setLevel(logging.INFO)
+log = logging.getLogger(__name__)
+
+
+MAX_EMPLOYEENUMBER_USER = 20
+MAX_STANDARD_USER = 100
+MAX_USER = MAX_STANDARD_USER + MAX_EMPLOYEENUMBER_USER
+EMPLOYEENUMBER_RDN_START = 0
+
+USER_UID='user_'
+BASE_DISTINGUISHED = 'ou=distinguished,ou=people,%s' % (DEFAULT_SUFFIX)
+BASE_REGULAR = 'ou=regular,ou=people,%s' % (DEFAULT_SUFFIX)
+
+def _user_get_dn(no):
+ uid = '%s%d' % (USER_UID, no)
+ dn = 'uid=%s,%s' % (uid, BASE_REGULAR)
+ return (uid, dn)
+
+def add_user(server, no, init_val):
+ (uid, dn) = _user_get_dn(no)
+ log.fatal('Adding user (%s): ' % dn)
+ server.add_s(Entry((dn, {'objectclass': ['top', 'person', 'organizationalPerson', 'inetOrgPerson'],
+ 'uid': [uid],
+ 'sn' : [uid],
+ 'cn' : [uid],
+ 'employeeNumber': init_val})))
+ return dn
+
+def _employeenumber_user_get_dn(no):
+ employeeNumber = str(no)
+ dn = 'employeeNumber=%s,%s' % (employeeNumber, BASE_DISTINGUISHED)
+ return (employeeNumber, dn)
+
+def add_employeenumber_user(server, no):
+ (uid, dn) = _employeenumber_user_get_dn(EMPLOYEENUMBER_RDN_START + no)
+ log.fatal('Adding user (%s): ' % dn)
+ server.add_s(Entry((dn, {'objectclass': ['top', 'person', 'organizationalPerson', 'inetOrgPerson'],
+ 'uid': [uid],
+ 'sn' : [uid],
+ 'cn' : [uid],
+ 'employeeNumber': str(EMPLOYEENUMBER_RDN_START + no)})))
+ return dn
+
+def save_stuff():
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_11 = '11'.encode()
+ value_1000 = '1000'.encode()
+ value_13 = '13'.encode()
+ value_14 = '14'.encode()
+
+ # Step 2
+ test_user_dn= add_user(M3, 0, value_11)
+ log.info('Adding %s on M3' % test_user_dn)
+ M3.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_11), (ldap.MOD_ADD, 'employeeNumber', value_1000)])
+ ents = M3.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == 1
+
+
+ # Step 3
+ # Check the entry is replicated on M1
+ for j in range(30):
+ try:
+ ent = M1.getEntry(test_user_dn, ldap.SCOPE_BASE,)
+ if not ent.hasAttr('employeeNumber'):
+ # wait for the MOD
+ log.info('M1 waiting for employeeNumber')
+ time.sleep(1)
+ continue;
+ break;
+ except ldap.NO_SUCH_OBJECT:
+ time.sleep(1)
+ pass
+ time.sleep(1)
+ ents = M1.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == 1
+
+ # Check the entry is replicated on M2
+ for j in range(30):
+ try:
+ ent = M2.getEntry(test_user_dn, ldap.SCOPE_BASE,)
+ if not ent.hasAttr('employeeNumber'):
+ # wait for the MOD
+ log.info('M2 waiting for employeeNumber')
+ time.sleep(1)
+ continue;
+
+ break;
+ except ldap.NO_SUCH_OBJECT:
+ time.sleep(1)
+ pass
+ time.sleep(1)
+ ents = M2.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == 1
+
+def test_ticket49658_init(topo):
+ """Specify a test case purpose or name here
+
+ :id: 0
+ :setup: 3 Master Instances
+ :steps:
+ 1. Create 3 suppliers
+ 2. Create on M3 MAX_USER test entries having a single-value attribute employeeNumber=11
+ and update it MOD_DEL 11 + MOD_ADD 1000
+ 3. Check they are replicated on M1 and M2
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_11 = '11'.encode()
+ value_1000 = '1000'.encode()
+
+ # Step 2
+ M3.add_s(Entry((BASE_DISTINGUISHED, {'objectclass': ['top', 'organizationalUnit'],
+ 'ou': ['distinguished']})))
+ for i in range(MAX_EMPLOYEENUMBER_USER):
+ test_user_dn= add_employeenumber_user(M3, i)
+ log.info('Adding %s on M3' % test_user_dn)
+ ents = M3.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == (i + 1)
+
+ M3.add_s(Entry((BASE_REGULAR, {'objectclass': ['top', 'organizationalUnit'],
+ 'ou': ['regular']})))
+ for i in range(MAX_STANDARD_USER):
+ test_user_dn= add_user(M3, i, value_11)
+ log.info('Adding %s on M3' % test_user_dn)
+ M3.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_11), (ldap.MOD_ADD, 'employeeNumber', value_1000)])
+ ents = M3.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == (MAX_EMPLOYEENUMBER_USER + i + 1)
+
+
+ # Step 3
+ # Check the last entry is replicated on M1
+ (uid, test_user_dn) = _user_get_dn(MAX_STANDARD_USER - 1)
+ for j in range(30):
+ try:
+ ent = M1.getEntry(test_user_dn, ldap.SCOPE_BASE,)
+ if not ent.hasAttr('employeeNumber'):
+ # wait for the MOD
+ log.info('M1 waiting for employeeNumber')
+ time.sleep(1)
+ continue;
+ break;
+ except ldap.NO_SUCH_OBJECT:
+ time.sleep(1)
+ pass
+ time.sleep(1)
+ ents = M1.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_USER
+
+ # Check the last entry is replicated on M2
+ for j in range(30):
+ try:
+ ent = M2.getEntry(test_user_dn, ldap.SCOPE_BASE,)
+ if not ent.hasAttr('employeeNumber'):
+ # wait for the MOD
+ log.info('M2 waiting for employeeNumber')
+ time.sleep(1)
+ continue;
+
+ break;
+ except ldap.NO_SUCH_OBJECT:
+ time.sleep(1)
+ pass
+ time.sleep(1)
+ ents = M2.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_USER
+
+def test_ticket49658_0(topo):
+ """Do MOD(DEL+ADD) and replicate MOST RECENT first
+ M1: MOD(DEL+ADD) -> V1
+ M2: MOD(DEL+ADD) -> V1
+ expected: V1
+
+ :id: 0
+ :setup: 3 Master Instances
+ 1. using user_0 where employNumber=1000
+ :steps:
+ 1. Create 3 suppliers
+ 2. Isolate M1 and M2 by pausing the replication agreements
+ 3. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 4. On M2 do MOD_DEL 1000 + MOD_ADD_13
+ 5. Enable replication agreement M2 -> M3, so that update step 6 is replicated first
+ 6. Enable replication agreement M1 -> M3, so that update step 5 is replicated second
+ 7. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'.encode()
+ last = '0'
+ value_end = last.encode()
+ theFilter = '(employeeNumber=%s)' % last
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 2
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 3
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ M1.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_1000), (ldap.MOD_ADD, 'employeeNumber', value_end)])
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 4
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M2.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_1000), (ldap.MOD_ADD, 'employeeNumber', value_end)])
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+def test_ticket49658_1(topo):
+ """Do MOD(DEL+ADD) and replicate OLDEST first
+ M2: MOD(DEL+ADD) -> V1
+ M1: MOD(DEL+ADD) -> V1
+ expected: V1
+
+ :id: 1
+ :setup: 3 Master Instances
+ 1. using user_1 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M2 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'.encode()
+ last = '1'
+ value_end = last.encode()
+ theFilter = '(employeeNumber=%s)' % last
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(1))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M2.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_1000), (ldap.MOD_ADD, 'employeeNumber', value_end)])
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M1.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_1000), (ldap.MOD_ADD, 'employeeNumber', value_end)])
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+def test_ticket49658_2(topo):
+ """Do MOD(ADD+DEL) and replicate OLDEST first
+ M2: MOD(ADD+DEL) -> V1
+ M1: MOD(ADD+DEL) -> V1
+ expected: V1
+
+ :id: 2
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M2 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'.encode()
+ last = '2'
+ value_end = last.encode()
+ theFilter = '(employeeNumber=%s)' % last
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M2.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end),(ldap.MOD_DELETE, 'employeeNumber', value_1000)])
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M1.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end), (ldap.MOD_DELETE, 'employeeNumber', value_1000)])
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+def test_ticket49658_3(topo):
+ """Do MOD(ADD+DEL) and replicate MOST RECENT first
+ M1: MOD(ADD+DEL) -> V1
+ M2: MOD(ADD+DEL) -> V1
+ expected: V1
+ :id: 3
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_DEL 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'.encode()
+ last = '3'
+ value_end = last.encode()
+ theFilter = '(employeeNumber=%s)' % last
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ M1.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end),(ldap.MOD_DELETE, 'employeeNumber', value_1000)])
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M2.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end), (ldap.MOD_DELETE, 'employeeNumber', value_1000)])
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+def test_ticket49658_4(topo):
+ """Do MOD(ADD+DEL) MOD(REPL) and replicate MOST RECENT first
+ M1: MOD(ADD+DEL) -> V1
+ M2: MOD(REPL) -> V1
+ expected: V1
+
+ :id: 4
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'.encode()
+ last = '4'
+ value_end = last.encode()
+ theFilter = '(employeeNumber=%s)' % last
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ M1.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end),(ldap.MOD_DELETE, 'employeeNumber', value_1000)])
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M2.modify_s(test_user_dn, [(ldap.MOD_REPLACE, 'employeeNumber', value_end)])
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+def test_ticket49658_5(topo):
+ """Do MOD(REPL) MOD(ADD+DEL) and replicate MOST RECENT first
+ M1: MOD(REPL) -> V1
+ M2: MOD(ADD+DEL) -> V1
+ expected: V1
+ :id: 5
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'.encode()
+ last = '5'
+ value_end = last.encode()
+ theFilter = '(employeeNumber=%s)' % last
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ M1.modify_s(test_user_dn, [(ldap.MOD_REPLACE, 'employeeNumber', value_end)])
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M2.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end),(ldap.MOD_DELETE, 'employeeNumber', value_1000)])
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+def test_ticket49658_6(topo):
+ """Do
+ M1: MOD(REPL) -> V1
+ M2: MOD(ADD+DEL) -> V2
+ expected: V2
+
+ :id: 6
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '6'
+ value_S1 = '6.1'
+ value_S2 = '6.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_ADD, 'employeeNumber', value_S2.encode()),(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode())],
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_7(topo):
+ """Do
+ M1: MOD(ADD+DEL) -> V1
+ M2: MOD(REPL) -> V2
+ expected: V2
+
+ :id: 7
+ :setup: 3 Master Instances
+ :steps:
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '7'
+ value_S1 = '7.1'
+ value_S2 = '7.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_ADD, 'employeeNumber', value_S1.encode()),(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_8(topo):
+ """Do
+ M1: MOD(DEL+ADD) -> V1
+ M2: MOD(REPL) -> V2
+ expected: V2
+
+ :id: 8
+ :setup: 3 Master Instances
+ :steps:
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '8'
+ value_S1 = '8.1'
+ value_S2 = '8.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+def test_ticket49658_9(topo):
+ """Do
+ M1: MOD(REPL) -> V1
+ M2: MOD(DEL+ADD) -> V2
+ expected: V2
+
+ :id: 9
+ :setup: 3 Master Instances
+ :steps:
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '9'
+ value_S1 = '9.1'
+ value_S2 = '9.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+
+def test_ticket49658_10(topo):
+ """Do
+ M1: MOD(REPL) -> V1
+ M2: MOD(REPL) -> V2
+ expected: V2
+
+ :id: 10
+ :setup: 3 Master Instances
+ :steps:
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '10'
+ value_S1 = '10.1'
+ value_S2 = '10.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+
+def test_ticket49658_11(topo):
+ """Do
+ M2: MOD(REPL) -> V2
+ M1: MOD(REPL) -> V1
+ expected: V1
+
+ :id: 11
+ :setup: 3 Master Instances
+ :steps:
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '11'
+ value_S1 = '11.1'
+ value_S2 = '11.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_12(topo):
+ """Do
+ M2: MOD(ADD+DEL) -> V2
+ M1: MOD(REPL) -> V1
+ expected: V1
+
+ :id: 12
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '12'
+ value_S1 = '12.1'
+ value_S2 = '12.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_ADD, 'employeeNumber', value_S2.encode()),(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode())],
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_13(topo):
+ """Do
+ M2: MOD(DEL+ADD) -> V2
+ M1: MOD(REPL) -> V1
+ expected: V1
+
+ :id: 13
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '13'
+ value_S1 = '13.1'
+ value_S2 = '13.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+def test_ticket49658_14(topo):
+ """Do
+ M2: MOD(DEL+ADD) -> V2
+ M1: MOD(DEL+ADD) -> V1
+ expected: V1
+
+ :id: 14
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '14'
+ value_S1 = '14.1'
+ value_S2 = '14.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_15(topo):
+ """Do
+ M2: MOD(ADD+DEL) -> V2
+ M1: MOD(DEL+ADD) -> V1
+ expected: V1
+
+ :id: 15
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '15'
+ value_S1 = '15.1'
+ value_S2 = '15.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_ADD, 'employeeNumber', value_S2.encode()),(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode())],
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+def _resume_ra_M1_then_M2(M1, M2, M3):
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ time.sleep(4)
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+ time.sleep(4)
+
+def _resume_ra_M2_then_M1(M1, M2, M3):
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+ time.sleep(4)
+
+
+def test_ticket49658_16(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V1
+ expected: V1
+ resume order: M2, M1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '1'
+ last = '1'
+ value_S1 = '1.1'
+ value_S2 = value_S1
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S2_MODRDN": value_S2,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+def test_ticket49658_17(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ expected: V2
+ resume order: M2 then M1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '2'
+ last = '2'
+ value_S1 = '2.1'
+ value_S2 = '2.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_18(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ expected: V2
+ resume order: M1 then M2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '2'
+ last = '3'
+ value_S1 = '3.1'
+ value_S2 = '3.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_19(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ Replicate order: M2 then M1
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '3'
+ last = '4'
+ value_S1 = '4.1'
+ value_S2 = '4.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_20(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ Replicate order: M1 then M2
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '3'
+ last = '5'
+ value_S1 = '5.1'
+ value_S2 = '5.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_21(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(DEL/ADD) -> V1
+ Replicate order: M2 then M1
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '3'
+ last = '6'
+ value_S1 = '6.1'
+ value_S2 = '6.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_22(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(DEL/ADD) -> V1
+ Replicate: M1 then M2
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '3'
+ last = '7'
+ value_S1 = '7.1'
+ value_S2 = '7.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_23(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MOD(REPL) -> V2
+ Replicate order: M2 then M1
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '8'
+ value_S1 = '8.1'
+ value_S2 = '8.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_24(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MOD(REPL) -> V2
+ Replicate order: M1 then M2
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '9'
+ value_S1 = '9.1'
+ value_S2 = '9.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_25(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MOD(DEL/ADD) -> V2
+ Replicate order: M1 then M2
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '10'
+ value_S1 = '10.1'
+ value_S2 = '10.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S2.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_26(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MOD(DEL/ADD) -> V2
+ Replicate order: M2 then M1
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '11'
+ value_S1 = '11.1'
+ value_S2 = '11.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S2.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_27(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(DEL/ADD) -> V1
+ M2: MOD(REPL) -> V2
+ Replicate order: M1 then M2
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '12'
+ value_S1 = '12.1'
+ value_S2 = '12.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_28(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(DEL/ADD) -> V1
+ M2: MOD(REPL) -> V2
+ Replicate order: M2 then M1
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '13'
+ value_S1 = '13.1'
+ value_S2 = '13.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+def test_ticket49658_29(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(DEL/ADD) -> V1
+ M2: MOD(DEL/ADD) -> V2
+ Replicate order: M1 then M2
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '14'
+ value_S1 = '14.1'
+ value_S2 = '14.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S2.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_30(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(DEL/ADD) -> V1
+ M2: MOD(DEL/ADD) -> V2
+ Replicate order: M2 then M1
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '15'
+ value_S1 = '15.1'
+ value_S2 = '15.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S2.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_31(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MOD(REPL) -> V2
+ M2: MODRDN -> V1
+ Replicate order: M2 then M1
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '16'
+ value_S1 = '16.1'
+ value_S2 = '16.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN_1": value_S2,
+ "S2_MODRDN_2": value_S1,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_1"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_1"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN_1"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ description["S2"].rename_s(new_test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_2"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_2"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+def test_ticket49658_32(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MOD(REPL) -> V2
+ M2: MODRDN -> V1
+ Replicate order: M1 then M2
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '17'
+ value_S1 = '17.1'
+ value_S2 = '17.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN_1": value_S2,
+ "S2_MODRDN_2": value_S1,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_1"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_1"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN_1"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ description["S2"].rename_s(new_test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_2"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_2"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_33(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MODRDN -> V1
+ Replicate order: M2 then M1
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '18'
+ value_S1 = '18.1'
+ value_S2 = '18.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MODRDN_1": value_S2,
+ "S2_MODRDN_2": value_S1,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_1"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_1"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN_1"])
+ description["S2"].rename_s(new_test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_2"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_2"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_34(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MODRDN -> V1
+ Replicate order: M1 then M2
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '19'
+ value_S1 = '19.1'
+ value_S2 = '19.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MODRDN_1": value_S2,
+ "S2_MODRDN_2": value_S1,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_1"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_1"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN_1"])
+ description["S2"].rename_s(new_test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_2"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_2"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+if __name__ == '__main__':
+ # Run isolated
+ # -s for DEBUG mode
+ CURRENT_FILE = os.path.realpath(__file__)
+ pytest.main(["-s", CURRENT_FILE])
+
diff --git a/ldap/servers/slapd/entrywsi.c b/ldap/servers/slapd/entrywsi.c
index 58f7870..080eb15 100644
--- a/ldap/servers/slapd/entrywsi.c
+++ b/ldap/servers/slapd/entrywsi.c
@@ -359,6 +359,13 @@ entry_add_present_attribute_wsi(Slapi_Entry *e, Slapi_Attr *a)
* Preserves LDAP Information Model constraints,
* returning an LDAP result code.
*/
+static void entry_dump_stateinfo(char *msg, Slapi_Entry* e);
+static Slapi_Value *attr_most_recent_deleted_value(Slapi_Attr *a);
+static void resolve_single_valued_two_values(Slapi_Entry *e, Slapi_Attr *a, int attribute_state, Slapi_Value *current_value, Slapi_Value *second_current_value);
+static void resolve_single_valued_check_restore_deleted_value(Slapi_Entry *e, Slapi_Attr *a);
+static void resolve_single_valued_zap_current(Slapi_Entry *e, Slapi_Attr *a);
+static void resolve_single_valued_set_adcsn(Slapi_Attr *a);
+static void resolve_single_valued_zap_deleted(Slapi_Attr *a);
static void resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribute_state);
static void resolve_attribute_state_deleted_to_present(Slapi_Entry *e, Slapi_Attr *a, Slapi_Value **valuestoupdate);
static void resolve_attribute_state_present_to_deleted(Slapi_Entry *e, Slapi_Attr *a, Slapi_Value **valuestoupdate);
@@ -387,6 +394,20 @@ entry_add_present_values_wsi(Slapi_Entry *e, const char *type, struct berval **b
return retVal;
}
+/* Used for debug purpose, it dumps into the error log the
+ * entry with the replication stateinfo
+ */
+static void
+entry_dump_stateinfo(char *msg, Slapi_Entry* e)
+{
+ char *s;
+ int32_t len = 0;
+
+ s = slapi_entry2str_with_options(e, &len, SLAPI_DUMP_STATEINFO);
+ slapi_log_err(SLAPI_LOG_ERR, msg, "%s\n", s);
+ slapi_ch_free((void **)&s);
+}
+
static int
entry_add_present_values_wsi_single_valued(Slapi_Entry *e, const char *type, struct berval **bervals, const CSN *csn, int urp, long flags)
{
@@ -705,6 +726,10 @@ entry_delete_present_values_wsi_single_valued(Slapi_Entry *e, const char *type,
/* The attribute is single valued and the value was successful deleted */
/* but there could have been an add in the same operation, so double check */
if (valueset_isempty(&a->a_present_values)) {
+ /* A doubt here, a direct update deletes the last value
+ * of a single valued attribute. It will only contain deleted values.
+ * Why not setting the adcsn (attr_set_deletion_csn) ?
+ */
entry_present_attribute_to_deleted_attribute(e, a);
}
} else if (retVal != LDAP_SUCCESS) {
@@ -1229,169 +1254,254 @@ resolve_attribute_state_present_to_deleted(Slapi_Entry *e, Slapi_Attr *a, Slapi_
}
}
-static void
-resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribute_state)
+/* Retrieve from the deleted values the one that
+ * was the most recently deleted. Based on its vdcsn
+ */
+static Slapi_Value *
+attr_most_recent_deleted_value(Slapi_Attr *a)
{
- Slapi_Value *current_value = NULL;
- Slapi_Value *pending_value = NULL;
- Slapi_Value *new_value = NULL;
- const CSN *current_value_vucsn;
- const CSN *pending_value_vucsn;
- const CSN *pending_value_vdcsn;
- const CSN *adcsn;
+ Slapi_Value *v, *most_recent_v;
int i;
+ CSN *vdcsn, *most_recent_vdcsn;
- /*
- * this call makes sure that the attribute does not have a pending_value
- * or deletion_csn which is before the current_value.
- */
- i = slapi_attr_first_value(a, ¤t_value);
- if (i != -1) {
- slapi_attr_next_value(a, i, &new_value);
- }
- attr_first_deleted_value(a, &pending_value);
- /* purge_attribute_state_single_valued */
- adcsn = attr_get_deletion_csn(a);
- current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
- pending_value_vucsn = value_get_csn(pending_value, CSN_TYPE_VALUE_UPDATED);
- pending_value_vdcsn = value_get_csn(pending_value, CSN_TYPE_VALUE_DELETED);
- if ((pending_value != NULL && (csn_compare(adcsn, pending_value_vucsn) < 0)) ||
- (pending_value == NULL && (csn_compare(adcsn, current_value_vucsn) < 0))) {
- attr_set_deletion_csn(a, NULL);
- adcsn = NULL;
+ vdcsn = NULL;
+ most_recent_vdcsn = NULL;
+ i = attr_first_deleted_value(a, &v);
+ most_recent_v = v;
+
+ while (i != -1) {
+ vdcsn = value_get_csn(v, CSN_TYPE_VALUE_DELETED);
+
+ if (csn_compare((const CSN *)most_recent_vdcsn, (const CSN *)vdcsn) < 0) {
+ most_recent_v = v;
+ most_recent_vdcsn = vdcsn;
+ }
+ i = attr_next_deleted_value(a, i, &v);
}
+ return most_recent_v;
+}
- /* in the case of the following:
- * add: value2
- * delete: value1
- * we will have current_value with VUCSN CSN1
- * and pending_value with VDCSN CSN2
- * and new_value == NULL
- * current_value != pending_value
- * and
- * VUCSN == VDCSN (ignoring subseq)
- * even though value1.VDCSN > value2.VUCSN
- * value2 should still win because the value is _different_
- */
- if (current_value && pending_value && !new_value && !adcsn &&
- (0 != slapi_value_compare(a, current_value, pending_value)) &&
- (0 == csn_compare_ext(current_value_vucsn, pending_value_vdcsn, CSN_COMPARE_SKIP_SUBSEQ))) {
- /* just remove the deleted value */
- entry_deleted_value_to_zapped_value(a, pending_value);
- pending_value = NULL;
- } else if (current_value && pending_value && !new_value && adcsn &&
- (attribute_state == ATTRIBUTE_DELETED) &&
- current_value_vucsn && !pending_value_vucsn && pending_value_vdcsn &&
- (csn_compare(current_value_vucsn, pending_value_vdcsn) > 0) &&
- (csn_compare(adcsn, pending_value_vdcsn) == 0)) {
- /* in the case of the following:
- * beginning attr state is a deleted value
- * incoming operation is
- * add: newvalue
- * attribute_state is ATTRIBUTE_DELETED
- * so we have both a current_value and a pending_value
- * new_value is NULL
- * current_value_vucsn is CSN1
- * pending_value_vucsn is NULL
- * pending_value_vdcsn is CSN2
- * adcsn is CSN2 == pending_value_vdcsn
- * CSN1 > CSN2
- * since the pending_value is deleted, and the current_value has
- * a greater CSN, we should keep the current_value and zap
- * the pending_value
+/* This routine applies for single valued attribute.
+ * The attribute has two current values, it keeps the most recent one
+ * and zap the oldest
+ */
+static void
+resolve_single_valued_two_values(Slapi_Entry *e, Slapi_Attr *a, int attribute_state, Slapi_Value *current_value, Slapi_Value *second_current_value)
+{
+
+ CSN *current_value_vucsn;
+ CSN *second_current_value_vucsn;
+ Slapi_Value *value_to_zap;
+
+ current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
+ second_current_value_vucsn = value_get_csn(second_current_value, CSN_TYPE_VALUE_UPDATED);
+
+ /* First determine which present value will be zapped */
+ if (csn_compare((const CSN *)second_current_value_vucsn, (const CSN *)current_value_vucsn) < 0) {
+ /*
+ * The second value is older but was distinguished at the time the current value was added
+ * then the second value should become current
*/
- /* just remove the deleted value */
- entry_deleted_value_to_zapped_value(a, pending_value);
- /* move the attribute to the present attributes list */
- entry_deleted_attribute_to_present_attribute(e, a);
- pending_value = NULL;
- attr_set_deletion_csn(a, NULL);
- return; /* we are done - we are keeping the present value */
- } else if (new_value == NULL) {
- /* check if the pending value should become the current value */
- if (pending_value != NULL) {
- if (!value_distinguished_at_csn(e, a, current_value, pending_value_vucsn)) {
- /* attribute.current_value = attribute.pending_value; */
- /* attribute.pending_value = NULL; */
- entry_present_value_to_zapped_value(a, current_value);
- entry_deleted_value_to_present_value(a, pending_value);
- current_value = pending_value;
- pending_value = NULL;
- current_value_vucsn = pending_value_vucsn;
- pending_value_vucsn = NULL;
- }
+ if (value_distinguished_at_csn(e, a, second_current_value, (const CSN *)current_value_vucsn)) {
+ value_to_zap = current_value;
+ } else {
+ /* The second value being not distinguished, zap it as it is a single valued attribute */
+ value_to_zap = second_current_value;
}
- /* check if the current value should be deleted */
- if (current_value != NULL) {
- if (csn_compare(adcsn, current_value_vucsn) > 0) /* check if the attribute was deleted after the value was last updated */
- {
- if (!value_distinguished_at_csn(e, a, current_value, current_value_vucsn)) {
- entry_present_value_to_zapped_value(a, current_value);
- current_value = NULL;
- current_value_vucsn = NULL;
- }
- }
+
+ } else {
+ /* Here the current_value is older than the second_current_value */
+ if (value_distinguished_at_csn(e, a, current_value, (const CSN *)second_current_value_vucsn)) {
+ /* current_value was distinguished at the time the second value was added
+ * then the current_value should become the current */
+ value_to_zap = second_current_value;
+ } else {
+ value_to_zap = current_value;
}
- } else /* addition of a new value */
- {
- const CSN *new_value_vucsn = value_get_csn(new_value, CSN_TYPE_VALUE_UPDATED);
- if (csn_compare(new_value_vucsn, current_value_vucsn) < 0) {
- /*
- * if the new value was distinguished at the time the current value was added
- * then the new value should become current
+ }
+ entry_present_value_to_zapped_value(a, value_to_zap);
+
+
+
+}
+
+/* This routine applies for single valued attribute.
+ * It checks if the deleted value is more recent than
+ * the present one. If it is, it resurect the deleted value
+ *
+ * This function leaves untouch the adcsn
+ */
+static void
+resolve_single_valued_check_restore_deleted_value(Slapi_Entry *e, Slapi_Attr *a)
+{
+ Slapi_Value *deleted_value = NULL;
+ Slapi_Value *current_value = NULL;
+
+ /* Retrieve the deleted and current value */
+ deleted_value = attr_most_recent_deleted_value(a);
+ if (deleted_value == NULL) {
+ return;
+ }
+ slapi_attr_first_value(a, ¤t_value);
+
+ if (current_value == NULL) {
+ /* An attribute needs a present value */
+ entry_deleted_value_to_present_value(a, deleted_value);
+ } else {
+ CSN *current_value_vucsn;
+ CSN *deleted_value_vucsn;
+ CSN *deleted_value_vdcsn;
+
+ deleted_value_vucsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_UPDATED);
+ deleted_value_vdcsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_DELETED);
+ current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
+ if (deleted_value_vucsn &&
+ !value_distinguished_at_csn(e, a, current_value, (const CSN *)deleted_value_vucsn) &&
+ (csn_compare((const CSN *)current_value_vucsn, (const CSN *)deleted_value_vucsn) < 0) &&
+ (csn_compare((const CSN *)deleted_value_vdcsn, (const CSN *)current_value_vucsn) < 0)) {
+ /* the condition to resurrect the deleted value is
+ * - it is more recent than the current value
+ * - its value was deleted before the current value
+ * - the current value is not distinguished
*/
- if (value_distinguished_at_csn(e, a, new_value, current_value_vucsn)) {
- /* attribute.pending_value = attribute.current_value */
- /* attribute.current_value = new_value */
- if (pending_value == NULL) {
- entry_present_value_to_deleted_value(a, current_value);
- } else {
- entry_present_value_to_zapped_value(a, current_value);
- }
- pending_value = current_value;
- current_value = new_value;
- new_value = NULL;
- pending_value_vucsn = current_value_vucsn;
- current_value_vucsn = new_value_vucsn;
- } else {
- /* new_value= NULL */
- entry_present_value_to_zapped_value(a, new_value);
- new_value = NULL;
- }
- } else /* new value is after the current value */
- {
- if (!value_distinguished_at_csn(e, a, current_value, new_value_vucsn)) {
- /* attribute.current_value = new_value */
- entry_present_value_to_zapped_value(a, current_value);
- current_value = new_value;
- new_value = NULL;
- current_value_vucsn = new_value_vucsn;
- } else /* value is distinguished - check if we should replace the current pending value */
- {
- if (csn_compare(new_value_vucsn, pending_value_vucsn) > 0) {
- /* attribute.pending_value = new_value */
- entry_deleted_value_to_zapped_value(a, pending_value);
- entry_present_value_to_deleted_value(a, new_value);
- pending_value = new_value;
- new_value = NULL;
- pending_value_vucsn = new_value_vucsn;
- }
- }
+ entry_present_value_to_zapped_value(a, current_value);
+ entry_deleted_value_to_present_value(a, deleted_value);
}
}
+}
+/* This function deals with single valued attribute
+ * It zap the current value if the adcsn is more recent and the value is not distinguished
+ */
+static void
+resolve_single_valued_zap_current(Slapi_Entry *e, Slapi_Attr *a)
+{
+ Slapi_Value *current_value = NULL;
+ CSN *current_value_vucsn;
+ CSN *adcsn;
- /*
- * This call ensures that the attribute does not have a pending_value
- * or a deletion_csn that is earlier than the current_value.
+ /* check if the current value should be deleted because
+ * older than adcsn and not distinguished
*/
- /* purge_attribute_state_single_valued */
- if ((pending_value != NULL && (csn_compare(adcsn, pending_value_vucsn) < 0)) ||
- (pending_value == NULL && (csn_compare(adcsn, current_value_vucsn) < 0))) {
+ slapi_attr_first_value(a, ¤t_value);
+ current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
+ adcsn = attr_get_deletion_csn(a);
+ if (current_value != NULL) {
+ if (csn_compare((const CSN *)adcsn, (const CSN *) current_value_vucsn) > 0) {
+ /* the attribute was deleted after the value was last updated */
+ if (!value_distinguished_at_csn(e, a, current_value, (const CSN *) current_value_vucsn)) {
+ entry_present_value_to_zapped_value(a, current_value);
+ }
+ }
+ }
+}
+/* This function deals with single valued attribute
+ * It reset the adcsn if
+ * - there is no deleted value and current value is more recent than the adcsn
+ * - there is a deleted value and it is more recent than the adcsn
+ */
+static void
+resolve_single_valued_set_adcsn(Slapi_Attr *a)
+{
+ Slapi_Value *deleted_value = NULL;
+ Slapi_Value *current_value = NULL;
+ CSN *current_value_vucsn;
+ CSN *deleted_value_vucsn;
+ CSN *adcsn;
+
+ slapi_attr_first_value(a, ¤t_value);
+ current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
+ deleted_value = attr_most_recent_deleted_value(a);
+ deleted_value_vucsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_UPDATED);
+ adcsn = attr_get_deletion_csn(a);
+ if ((deleted_value != NULL && (csn_compare(adcsn, (const CSN *) deleted_value_vucsn) < 0)) ||
+ (deleted_value == NULL && (csn_compare(adcsn, (const CSN *) current_value_vucsn) < 0))) {
attr_set_deletion_csn(a, NULL);
- adcsn = NULL;
}
+}
+/* This function deals with single valued attribute
+ * It checks if the deleted value worth to be kept
+ *
+ * deleted value is zapped if
+ * - it is the result of MOD_REPL that is older than current value
+ * - It is the result of MOD_DEL_<value> that is belong to the same operation that set the current value
+ */
+static void
+resolve_single_valued_zap_deleted(Slapi_Attr *a)
+{
+ Slapi_Value *deleted_value = NULL;
+ Slapi_Value *current_value = NULL;
+ CSN *current_value_vucsn;
+ CSN *deleted_value_vucsn;
+ CSN *deleted_value_vdcsn;
+ CSN *deleted_value_csn;
+ PRBool deleted_on_mod_del = PR_FALSE; /* flag if a value was deleted specifically */
+
+ /* Now determine if the deleted value worth to be kept */
+ slapi_attr_first_value(a, ¤t_value);
+ current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
+
+ deleted_value = attr_most_recent_deleted_value(a);
+ deleted_value_vucsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_UPDATED);
+ deleted_value_vdcsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_DELETED);
+
+ /* get the appropriate csn to take into consideration: either from MOD_REPL or from MOD_DEL_specific */
+ if (csn_compare((const CSN *) deleted_value_vdcsn, (const CSN *) deleted_value_vucsn) <= 0) {
+ deleted_value_csn = deleted_value_vucsn;
+ } else {
+ deleted_value_csn = deleted_value_vdcsn;
+ if (0 == csn_compare_ext((const CSN *) current_value_vucsn, (const CSN *) deleted_value_vdcsn, CSN_COMPARE_SKIP_SUBSEQ)) {
+ /* the deleted value was specifically delete in the same operation that set the current value */
+ deleted_on_mod_del = PR_TRUE;
+ }
+ }
+ if ((csn_compare((const CSN *) deleted_value_csn, (const CSN *) current_value_vucsn) < 0) || deleted_on_mod_del) {
+ entry_deleted_value_to_zapped_value(a, deleted_value);
+ }
+}
+
+/* This function deals with single valued attribute
+ * It does a set of cleanup in the current/deleted values in order
+ * to conform the schema, take care of distinguished values and only preserve the
+ * values that worth to be kept.
+ */
+static void
+resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribute_state)
+{
+ int32_t nbval, i;
+ Slapi_Value *current_value = NULL;
+
+ /* retrieve the current value(s) */
+ slapi_attr_get_numvalues(a, &nbval);
+ i = slapi_attr_first_value(a, ¤t_value);
+
+ /* If there are several values, first determine which value will be the current (present) one */
+ if (nbval > 1) {
+ /* There are several values for a single valued attribute, keep the most recent one */
+ if (i == -1) {
+ slapi_log_err(SLAPI_LOG_ERR, "resolve_attribute_state_single_valued", "Unexpected state of %s that contains more than one value but can not read the second\n", a->a_type);
+ } else {
+ Slapi_Value *second_current_value = NULL;
+
+ slapi_attr_next_value(a, i, &second_current_value);
+ resolve_single_valued_two_values(e, a, attribute_state, current_value, second_current_value);
+ }
+ }
+ /* There is only one current value (present value) */
+
+ /* Now determine if the deleted value needs to replace the current value */
+ resolve_single_valued_check_restore_deleted_value(e, a);
+
+ /* Now determine if the deleted value worth to be kept (vs. current value) */
+ resolve_single_valued_zap_deleted(a);
+
+ /* Now determine if the current value worth to be kept (vs. adcsn) */
+ resolve_single_valued_zap_current(e, a);
+
+ /* Now set the adcsn */
+ resolve_single_valued_set_adcsn(a);
- /* set attribute state */
+ /* set the attribute in the correct list in the entry: present or deleted */
+ slapi_attr_first_value(a, ¤t_value);
if (current_value == NULL) {
if (attribute_state == ATTRIBUTE_PRESENT) {
entry_present_attribute_to_deleted_attribute(e, a);
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years, 2 months
[389-ds-base] branch 389-ds-base-1.3.9 updated: Ticket 49658 - In replicated topology a single-valued attribute can diverge
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
tbordaz pushed a commit to branch 389-ds-base-1.3.9
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.3.9 by this push:
new 4c71cc2 Ticket 49658 - In replicated topology a single-valued attribute can diverge
4c71cc2 is described below
commit 4c71cc27caa3fb4338e6304b2cd8c4238a893521
Author: Thierry Bordaz <tbordaz(a)redhat.com>
AuthorDate: Tue May 15 16:45:56 2018 +0200
Ticket 49658 - In replicated topology a single-valued attribute can diverge
Bug Description:
When deleting a specific value of a single valued attribute,
the deleted value can be erronously resurrected.
Fix Description:
This second fix is a rewrite of entry state resolution.
The original function (resolve_attribute_state_single_valued) implemented
a main algorythm but it was heavily merged with resolution of specific cases.
It was too difficult to make the function understandable and preserving
the handling of the specific cases.
The risk of that rewrite fix is that I can not guarantee it fully covers
the set of specific cases
https://pagure.io/389-ds-base/issue/49658
Reviewed by: William Brown (Thanks !!)
Platforms tested: F27
Flag Day: no
Doc impact: no
---
dirsrvtests/tests/tickets/ticket49658_test.py | 4264 +++++++++++++++++++++++++
ldap/servers/slapd/entrywsi.c | 404 ++-
2 files changed, 4521 insertions(+), 147 deletions(-)
diff --git a/dirsrvtests/tests/tickets/ticket49658_test.py b/dirsrvtests/tests/tickets/ticket49658_test.py
new file mode 100644
index 0000000..53522df
--- /dev/null
+++ b/dirsrvtests/tests/tickets/ticket49658_test.py
@@ -0,0 +1,4264 @@
+import logging
+import pytest
+import os
+import ldap
+import time
+import sys
+print(sys.path)
+from lib389 import Entry
+from lib389._constants import DEFAULT_SUFFIX
+from lib389.idm.user import UserAccounts, TEST_USER_PROPERTIES
+from lib389.topologies import topology_m3 as topo
+
+DEBUGGING = os.getenv("DEBUGGING", default=False)
+if DEBUGGING:
+ logging.getLogger(__name__).setLevel(logging.DEBUG)
+else:
+ logging.getLogger(__name__).setLevel(logging.INFO)
+log = logging.getLogger(__name__)
+
+
+MAX_EMPLOYEENUMBER_USER = 20
+MAX_STANDARD_USER = 100
+MAX_USER = MAX_STANDARD_USER + MAX_EMPLOYEENUMBER_USER
+EMPLOYEENUMBER_RDN_START = 0
+
+USER_UID='user_'
+BASE_DISTINGUISHED = 'ou=distinguished,ou=people,%s' % (DEFAULT_SUFFIX)
+BASE_REGULAR = 'ou=regular,ou=people,%s' % (DEFAULT_SUFFIX)
+
+def _user_get_dn(no):
+ uid = '%s%d' % (USER_UID, no)
+ dn = 'uid=%s,%s' % (uid, BASE_REGULAR)
+ return (uid, dn)
+
+def add_user(server, no, init_val):
+ (uid, dn) = _user_get_dn(no)
+ log.fatal('Adding user (%s): ' % dn)
+ server.add_s(Entry((dn, {'objectclass': ['top', 'person', 'organizationalPerson', 'inetOrgPerson'],
+ 'uid': [uid],
+ 'sn' : [uid],
+ 'cn' : [uid],
+ 'employeeNumber': init_val})))
+ return dn
+
+def _employeenumber_user_get_dn(no):
+ employeeNumber = str(no)
+ dn = 'employeeNumber=%s,%s' % (employeeNumber, BASE_DISTINGUISHED)
+ return (employeeNumber, dn)
+
+def add_employeenumber_user(server, no):
+ (uid, dn) = _employeenumber_user_get_dn(EMPLOYEENUMBER_RDN_START + no)
+ log.fatal('Adding user (%s): ' % dn)
+ server.add_s(Entry((dn, {'objectclass': ['top', 'person', 'organizationalPerson', 'inetOrgPerson'],
+ 'uid': [uid],
+ 'sn' : [uid],
+ 'cn' : [uid],
+ 'employeeNumber': str(EMPLOYEENUMBER_RDN_START + no)})))
+ return dn
+
+def save_stuff():
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_11 = '11'.encode()
+ value_1000 = '1000'.encode()
+ value_13 = '13'.encode()
+ value_14 = '14'.encode()
+
+ # Step 2
+ test_user_dn= add_user(M3, 0, value_11)
+ log.info('Adding %s on M3' % test_user_dn)
+ M3.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_11), (ldap.MOD_ADD, 'employeeNumber', value_1000)])
+ ents = M3.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == 1
+
+
+ # Step 3
+ # Check the entry is replicated on M1
+ for j in range(30):
+ try:
+ ent = M1.getEntry(test_user_dn, ldap.SCOPE_BASE,)
+ if not ent.hasAttr('employeeNumber'):
+ # wait for the MOD
+ log.info('M1 waiting for employeeNumber')
+ time.sleep(1)
+ continue;
+ break;
+ except ldap.NO_SUCH_OBJECT:
+ time.sleep(1)
+ pass
+ time.sleep(1)
+ ents = M1.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == 1
+
+ # Check the entry is replicated on M2
+ for j in range(30):
+ try:
+ ent = M2.getEntry(test_user_dn, ldap.SCOPE_BASE,)
+ if not ent.hasAttr('employeeNumber'):
+ # wait for the MOD
+ log.info('M2 waiting for employeeNumber')
+ time.sleep(1)
+ continue;
+
+ break;
+ except ldap.NO_SUCH_OBJECT:
+ time.sleep(1)
+ pass
+ time.sleep(1)
+ ents = M2.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == 1
+
+def test_ticket49658_init(topo):
+ """Specify a test case purpose or name here
+
+ :id: 0
+ :setup: 3 Master Instances
+ :steps:
+ 1. Create 3 suppliers
+ 2. Create on M3 MAX_USER test entries having a single-value attribute employeeNumber=11
+ and update it MOD_DEL 11 + MOD_ADD 1000
+ 3. Check they are replicated on M1 and M2
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_11 = '11'.encode()
+ value_1000 = '1000'.encode()
+
+ # Step 2
+ M3.add_s(Entry((BASE_DISTINGUISHED, {'objectclass': ['top', 'organizationalUnit'],
+ 'ou': ['distinguished']})))
+ for i in range(MAX_EMPLOYEENUMBER_USER):
+ test_user_dn= add_employeenumber_user(M3, i)
+ log.info('Adding %s on M3' % test_user_dn)
+ ents = M3.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == (i + 1)
+
+ M3.add_s(Entry((BASE_REGULAR, {'objectclass': ['top', 'organizationalUnit'],
+ 'ou': ['regular']})))
+ for i in range(MAX_STANDARD_USER):
+ test_user_dn= add_user(M3, i, value_11)
+ log.info('Adding %s on M3' % test_user_dn)
+ M3.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_11), (ldap.MOD_ADD, 'employeeNumber', value_1000)])
+ ents = M3.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == (MAX_EMPLOYEENUMBER_USER + i + 1)
+
+
+ # Step 3
+ # Check the last entry is replicated on M1
+ (uid, test_user_dn) = _user_get_dn(MAX_STANDARD_USER - 1)
+ for j in range(30):
+ try:
+ ent = M1.getEntry(test_user_dn, ldap.SCOPE_BASE,)
+ if not ent.hasAttr('employeeNumber'):
+ # wait for the MOD
+ log.info('M1 waiting for employeeNumber')
+ time.sleep(1)
+ continue;
+ break;
+ except ldap.NO_SUCH_OBJECT:
+ time.sleep(1)
+ pass
+ time.sleep(1)
+ ents = M1.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_USER
+
+ # Check the last entry is replicated on M2
+ for j in range(30):
+ try:
+ ent = M2.getEntry(test_user_dn, ldap.SCOPE_BASE,)
+ if not ent.hasAttr('employeeNumber'):
+ # wait for the MOD
+ log.info('M2 waiting for employeeNumber')
+ time.sleep(1)
+ continue;
+
+ break;
+ except ldap.NO_SUCH_OBJECT:
+ time.sleep(1)
+ pass
+ time.sleep(1)
+ ents = M2.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_USER
+
+def test_ticket49658_0(topo):
+ """Do MOD(DEL+ADD) and replicate MOST RECENT first
+ M1: MOD(DEL+ADD) -> V1
+ M2: MOD(DEL+ADD) -> V1
+ expected: V1
+
+ :id: 0
+ :setup: 3 Master Instances
+ 1. using user_0 where employNumber=1000
+ :steps:
+ 1. Create 3 suppliers
+ 2. Isolate M1 and M2 by pausing the replication agreements
+ 3. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 4. On M2 do MOD_DEL 1000 + MOD_ADD_13
+ 5. Enable replication agreement M2 -> M3, so that update step 6 is replicated first
+ 6. Enable replication agreement M1 -> M3, so that update step 5 is replicated second
+ 7. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'.encode()
+ last = '0'
+ value_end = last.encode()
+ theFilter = '(employeeNumber=%s)' % last
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 2
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 3
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ M1.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_1000), (ldap.MOD_ADD, 'employeeNumber', value_end)])
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 4
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M2.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_1000), (ldap.MOD_ADD, 'employeeNumber', value_end)])
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+def test_ticket49658_1(topo):
+ """Do MOD(DEL+ADD) and replicate OLDEST first
+ M2: MOD(DEL+ADD) -> V1
+ M1: MOD(DEL+ADD) -> V1
+ expected: V1
+
+ :id: 1
+ :setup: 3 Master Instances
+ 1. using user_1 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M2 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'.encode()
+ last = '1'
+ value_end = last.encode()
+ theFilter = '(employeeNumber=%s)' % last
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(1))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M2.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_1000), (ldap.MOD_ADD, 'employeeNumber', value_end)])
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M1.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_1000), (ldap.MOD_ADD, 'employeeNumber', value_end)])
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+def test_ticket49658_2(topo):
+ """Do MOD(ADD+DEL) and replicate OLDEST first
+ M2: MOD(ADD+DEL) -> V1
+ M1: MOD(ADD+DEL) -> V1
+ expected: V1
+
+ :id: 2
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M2 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'.encode()
+ last = '2'
+ value_end = last.encode()
+ theFilter = '(employeeNumber=%s)' % last
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M2.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end),(ldap.MOD_DELETE, 'employeeNumber', value_1000)])
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M1.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end), (ldap.MOD_DELETE, 'employeeNumber', value_1000)])
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+def test_ticket49658_3(topo):
+ """Do MOD(ADD+DEL) and replicate MOST RECENT first
+ M1: MOD(ADD+DEL) -> V1
+ M2: MOD(ADD+DEL) -> V1
+ expected: V1
+ :id: 3
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_DEL 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'.encode()
+ last = '3'
+ value_end = last.encode()
+ theFilter = '(employeeNumber=%s)' % last
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ M1.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end),(ldap.MOD_DELETE, 'employeeNumber', value_1000)])
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M2.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end), (ldap.MOD_DELETE, 'employeeNumber', value_1000)])
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+def test_ticket49658_4(topo):
+ """Do MOD(ADD+DEL) MOD(REPL) and replicate MOST RECENT first
+ M1: MOD(ADD+DEL) -> V1
+ M2: MOD(REPL) -> V1
+ expected: V1
+
+ :id: 4
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'.encode()
+ last = '4'
+ value_end = last.encode()
+ theFilter = '(employeeNumber=%s)' % last
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ M1.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end),(ldap.MOD_DELETE, 'employeeNumber', value_1000)])
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M2.modify_s(test_user_dn, [(ldap.MOD_REPLACE, 'employeeNumber', value_end)])
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+def test_ticket49658_5(topo):
+ """Do MOD(REPL) MOD(ADD+DEL) and replicate MOST RECENT first
+ M1: MOD(REPL) -> V1
+ M2: MOD(ADD+DEL) -> V1
+ expected: V1
+ :id: 5
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'.encode()
+ last = '5'
+ value_end = last.encode()
+ theFilter = '(employeeNumber=%s)' % last
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ M1.modify_s(test_user_dn, [(ldap.MOD_REPLACE, 'employeeNumber', value_end)])
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M2.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end),(ldap.MOD_DELETE, 'employeeNumber', value_1000)])
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+def test_ticket49658_6(topo):
+ """Do
+ M1: MOD(REPL) -> V1
+ M2: MOD(ADD+DEL) -> V2
+ expected: V2
+
+ :id: 6
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '6'
+ value_S1 = '6.1'
+ value_S2 = '6.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_ADD, 'employeeNumber', value_S2.encode()),(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode())],
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_7(topo):
+ """Do
+ M1: MOD(ADD+DEL) -> V1
+ M2: MOD(REPL) -> V2
+ expected: V2
+
+ :id: 7
+ :setup: 3 Master Instances
+ :steps:
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '7'
+ value_S1 = '7.1'
+ value_S2 = '7.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_ADD, 'employeeNumber', value_S1.encode()),(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_8(topo):
+ """Do
+ M1: MOD(DEL+ADD) -> V1
+ M2: MOD(REPL) -> V2
+ expected: V2
+
+ :id: 8
+ :setup: 3 Master Instances
+ :steps:
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '8'
+ value_S1 = '8.1'
+ value_S2 = '8.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+def test_ticket49658_9(topo):
+ """Do
+ M1: MOD(REPL) -> V1
+ M2: MOD(DEL+ADD) -> V2
+ expected: V2
+
+ :id: 9
+ :setup: 3 Master Instances
+ :steps:
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '9'
+ value_S1 = '9.1'
+ value_S2 = '9.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+
+def test_ticket49658_10(topo):
+ """Do
+ M1: MOD(REPL) -> V1
+ M2: MOD(REPL) -> V2
+ expected: V2
+
+ :id: 10
+ :setup: 3 Master Instances
+ :steps:
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '10'
+ value_S1 = '10.1'
+ value_S2 = '10.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+
+def test_ticket49658_11(topo):
+ """Do
+ M2: MOD(REPL) -> V2
+ M1: MOD(REPL) -> V1
+ expected: V1
+
+ :id: 11
+ :setup: 3 Master Instances
+ :steps:
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '11'
+ value_S1 = '11.1'
+ value_S2 = '11.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_12(topo):
+ """Do
+ M2: MOD(ADD+DEL) -> V2
+ M1: MOD(REPL) -> V1
+ expected: V1
+
+ :id: 12
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '12'
+ value_S1 = '12.1'
+ value_S2 = '12.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_ADD, 'employeeNumber', value_S2.encode()),(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode())],
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_13(topo):
+ """Do
+ M2: MOD(DEL+ADD) -> V2
+ M1: MOD(REPL) -> V1
+ expected: V1
+
+ :id: 13
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '13'
+ value_S1 = '13.1'
+ value_S2 = '13.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+def test_ticket49658_14(topo):
+ """Do
+ M2: MOD(DEL+ADD) -> V2
+ M1: MOD(DEL+ADD) -> V1
+ expected: V1
+
+ :id: 14
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '14'
+ value_S1 = '14.1'
+ value_S2 = '14.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_15(topo):
+ """Do
+ M2: MOD(ADD+DEL) -> V2
+ M1: MOD(DEL+ADD) -> V1
+ expected: V1
+
+ :id: 15
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '15'
+ value_S1 = '15.1'
+ value_S2 = '15.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_ADD, 'employeeNumber', value_S2.encode()),(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode())],
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+def _resume_ra_M1_then_M2(M1, M2, M3):
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ time.sleep(4)
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+ time.sleep(4)
+
+def _resume_ra_M2_then_M1(M1, M2, M3):
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+ time.sleep(4)
+
+
+def test_ticket49658_16(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V1
+ expected: V1
+ resume order: M2, M1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '1'
+ last = '1'
+ value_S1 = '1.1'
+ value_S2 = value_S1
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S2_MODRDN": value_S2,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+def test_ticket49658_17(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ expected: V2
+ resume order: M2 then M1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '2'
+ last = '2'
+ value_S1 = '2.1'
+ value_S2 = '2.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_18(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ expected: V2
+ resume order: M1 then M2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '2'
+ last = '3'
+ value_S1 = '3.1'
+ value_S2 = '3.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_19(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ Replicate order: M2 then M1
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '3'
+ last = '4'
+ value_S1 = '4.1'
+ value_S2 = '4.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_20(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ Replicate order: M1 then M2
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '3'
+ last = '5'
+ value_S1 = '5.1'
+ value_S2 = '5.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_21(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(DEL/ADD) -> V1
+ Replicate order: M2 then M1
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '3'
+ last = '6'
+ value_S1 = '6.1'
+ value_S2 = '6.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_22(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(DEL/ADD) -> V1
+ Replicate: M1 then M2
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '3'
+ last = '7'
+ value_S1 = '7.1'
+ value_S2 = '7.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_23(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MOD(REPL) -> V2
+ Replicate order: M2 then M1
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '8'
+ value_S1 = '8.1'
+ value_S2 = '8.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_24(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MOD(REPL) -> V2
+ Replicate order: M1 then M2
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '9'
+ value_S1 = '9.1'
+ value_S2 = '9.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_25(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MOD(DEL/ADD) -> V2
+ Replicate order: M1 then M2
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '10'
+ value_S1 = '10.1'
+ value_S2 = '10.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S2.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_26(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MOD(DEL/ADD) -> V2
+ Replicate order: M2 then M1
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '11'
+ value_S1 = '11.1'
+ value_S2 = '11.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S2.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_27(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(DEL/ADD) -> V1
+ M2: MOD(REPL) -> V2
+ Replicate order: M1 then M2
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '12'
+ value_S1 = '12.1'
+ value_S2 = '12.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_28(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(DEL/ADD) -> V1
+ M2: MOD(REPL) -> V2
+ Replicate order: M2 then M1
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '13'
+ value_S1 = '13.1'
+ value_S2 = '13.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+def test_ticket49658_29(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(DEL/ADD) -> V1
+ M2: MOD(DEL/ADD) -> V2
+ Replicate order: M1 then M2
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '14'
+ value_S1 = '14.1'
+ value_S2 = '14.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S2.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_30(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(DEL/ADD) -> V1
+ M2: MOD(DEL/ADD) -> V2
+ Replicate order: M2 then M1
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '15'
+ value_S1 = '15.1'
+ value_S2 = '15.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S2.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_31(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MOD(REPL) -> V2
+ M2: MODRDN -> V1
+ Replicate order: M2 then M1
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '16'
+ value_S1 = '16.1'
+ value_S2 = '16.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN_1": value_S2,
+ "S2_MODRDN_2": value_S1,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_1"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_1"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN_1"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ description["S2"].rename_s(new_test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_2"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_2"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+def test_ticket49658_32(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MOD(REPL) -> V2
+ M2: MODRDN -> V1
+ Replicate order: M1 then M2
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '17'
+ value_S1 = '17.1'
+ value_S2 = '17.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN_1": value_S2,
+ "S2_MODRDN_2": value_S1,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_1"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_1"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN_1"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ description["S2"].rename_s(new_test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_2"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_2"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_33(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MODRDN -> V1
+ Replicate order: M2 then M1
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '18'
+ value_S1 = '18.1'
+ value_S2 = '18.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MODRDN_1": value_S2,
+ "S2_MODRDN_2": value_S1,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_1"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_1"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN_1"])
+ description["S2"].rename_s(new_test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_2"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_2"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_34(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MODRDN -> V1
+ Replicate order: M1 then M2
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '19'
+ value_S1 = '19.1'
+ value_S2 = '19.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MODRDN_1": value_S2,
+ "S2_MODRDN_2": value_S1,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_1"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_1"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN_1"])
+ description["S2"].rename_s(new_test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_2"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_2"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+if __name__ == '__main__':
+ # Run isolated
+ # -s for DEBUG mode
+ CURRENT_FILE = os.path.realpath(__file__)
+ pytest.main(["-s", CURRENT_FILE])
+
diff --git a/ldap/servers/slapd/entrywsi.c b/ldap/servers/slapd/entrywsi.c
index 58f7870..080eb15 100644
--- a/ldap/servers/slapd/entrywsi.c
+++ b/ldap/servers/slapd/entrywsi.c
@@ -359,6 +359,13 @@ entry_add_present_attribute_wsi(Slapi_Entry *e, Slapi_Attr *a)
* Preserves LDAP Information Model constraints,
* returning an LDAP result code.
*/
+static void entry_dump_stateinfo(char *msg, Slapi_Entry* e);
+static Slapi_Value *attr_most_recent_deleted_value(Slapi_Attr *a);
+static void resolve_single_valued_two_values(Slapi_Entry *e, Slapi_Attr *a, int attribute_state, Slapi_Value *current_value, Slapi_Value *second_current_value);
+static void resolve_single_valued_check_restore_deleted_value(Slapi_Entry *e, Slapi_Attr *a);
+static void resolve_single_valued_zap_current(Slapi_Entry *e, Slapi_Attr *a);
+static void resolve_single_valued_set_adcsn(Slapi_Attr *a);
+static void resolve_single_valued_zap_deleted(Slapi_Attr *a);
static void resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribute_state);
static void resolve_attribute_state_deleted_to_present(Slapi_Entry *e, Slapi_Attr *a, Slapi_Value **valuestoupdate);
static void resolve_attribute_state_present_to_deleted(Slapi_Entry *e, Slapi_Attr *a, Slapi_Value **valuestoupdate);
@@ -387,6 +394,20 @@ entry_add_present_values_wsi(Slapi_Entry *e, const char *type, struct berval **b
return retVal;
}
+/* Used for debug purpose, it dumps into the error log the
+ * entry with the replication stateinfo
+ */
+static void
+entry_dump_stateinfo(char *msg, Slapi_Entry* e)
+{
+ char *s;
+ int32_t len = 0;
+
+ s = slapi_entry2str_with_options(e, &len, SLAPI_DUMP_STATEINFO);
+ slapi_log_err(SLAPI_LOG_ERR, msg, "%s\n", s);
+ slapi_ch_free((void **)&s);
+}
+
static int
entry_add_present_values_wsi_single_valued(Slapi_Entry *e, const char *type, struct berval **bervals, const CSN *csn, int urp, long flags)
{
@@ -705,6 +726,10 @@ entry_delete_present_values_wsi_single_valued(Slapi_Entry *e, const char *type,
/* The attribute is single valued and the value was successful deleted */
/* but there could have been an add in the same operation, so double check */
if (valueset_isempty(&a->a_present_values)) {
+ /* A doubt here, a direct update deletes the last value
+ * of a single valued attribute. It will only contain deleted values.
+ * Why not setting the adcsn (attr_set_deletion_csn) ?
+ */
entry_present_attribute_to_deleted_attribute(e, a);
}
} else if (retVal != LDAP_SUCCESS) {
@@ -1229,169 +1254,254 @@ resolve_attribute_state_present_to_deleted(Slapi_Entry *e, Slapi_Attr *a, Slapi_
}
}
-static void
-resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribute_state)
+/* Retrieve from the deleted values the one that
+ * was the most recently deleted. Based on its vdcsn
+ */
+static Slapi_Value *
+attr_most_recent_deleted_value(Slapi_Attr *a)
{
- Slapi_Value *current_value = NULL;
- Slapi_Value *pending_value = NULL;
- Slapi_Value *new_value = NULL;
- const CSN *current_value_vucsn;
- const CSN *pending_value_vucsn;
- const CSN *pending_value_vdcsn;
- const CSN *adcsn;
+ Slapi_Value *v, *most_recent_v;
int i;
+ CSN *vdcsn, *most_recent_vdcsn;
- /*
- * this call makes sure that the attribute does not have a pending_value
- * or deletion_csn which is before the current_value.
- */
- i = slapi_attr_first_value(a, ¤t_value);
- if (i != -1) {
- slapi_attr_next_value(a, i, &new_value);
- }
- attr_first_deleted_value(a, &pending_value);
- /* purge_attribute_state_single_valued */
- adcsn = attr_get_deletion_csn(a);
- current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
- pending_value_vucsn = value_get_csn(pending_value, CSN_TYPE_VALUE_UPDATED);
- pending_value_vdcsn = value_get_csn(pending_value, CSN_TYPE_VALUE_DELETED);
- if ((pending_value != NULL && (csn_compare(adcsn, pending_value_vucsn) < 0)) ||
- (pending_value == NULL && (csn_compare(adcsn, current_value_vucsn) < 0))) {
- attr_set_deletion_csn(a, NULL);
- adcsn = NULL;
+ vdcsn = NULL;
+ most_recent_vdcsn = NULL;
+ i = attr_first_deleted_value(a, &v);
+ most_recent_v = v;
+
+ while (i != -1) {
+ vdcsn = value_get_csn(v, CSN_TYPE_VALUE_DELETED);
+
+ if (csn_compare((const CSN *)most_recent_vdcsn, (const CSN *)vdcsn) < 0) {
+ most_recent_v = v;
+ most_recent_vdcsn = vdcsn;
+ }
+ i = attr_next_deleted_value(a, i, &v);
}
+ return most_recent_v;
+}
- /* in the case of the following:
- * add: value2
- * delete: value1
- * we will have current_value with VUCSN CSN1
- * and pending_value with VDCSN CSN2
- * and new_value == NULL
- * current_value != pending_value
- * and
- * VUCSN == VDCSN (ignoring subseq)
- * even though value1.VDCSN > value2.VUCSN
- * value2 should still win because the value is _different_
- */
- if (current_value && pending_value && !new_value && !adcsn &&
- (0 != slapi_value_compare(a, current_value, pending_value)) &&
- (0 == csn_compare_ext(current_value_vucsn, pending_value_vdcsn, CSN_COMPARE_SKIP_SUBSEQ))) {
- /* just remove the deleted value */
- entry_deleted_value_to_zapped_value(a, pending_value);
- pending_value = NULL;
- } else if (current_value && pending_value && !new_value && adcsn &&
- (attribute_state == ATTRIBUTE_DELETED) &&
- current_value_vucsn && !pending_value_vucsn && pending_value_vdcsn &&
- (csn_compare(current_value_vucsn, pending_value_vdcsn) > 0) &&
- (csn_compare(adcsn, pending_value_vdcsn) == 0)) {
- /* in the case of the following:
- * beginning attr state is a deleted value
- * incoming operation is
- * add: newvalue
- * attribute_state is ATTRIBUTE_DELETED
- * so we have both a current_value and a pending_value
- * new_value is NULL
- * current_value_vucsn is CSN1
- * pending_value_vucsn is NULL
- * pending_value_vdcsn is CSN2
- * adcsn is CSN2 == pending_value_vdcsn
- * CSN1 > CSN2
- * since the pending_value is deleted, and the current_value has
- * a greater CSN, we should keep the current_value and zap
- * the pending_value
+/* This routine applies for single valued attribute.
+ * The attribute has two current values, it keeps the most recent one
+ * and zap the oldest
+ */
+static void
+resolve_single_valued_two_values(Slapi_Entry *e, Slapi_Attr *a, int attribute_state, Slapi_Value *current_value, Slapi_Value *second_current_value)
+{
+
+ CSN *current_value_vucsn;
+ CSN *second_current_value_vucsn;
+ Slapi_Value *value_to_zap;
+
+ current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
+ second_current_value_vucsn = value_get_csn(second_current_value, CSN_TYPE_VALUE_UPDATED);
+
+ /* First determine which present value will be zapped */
+ if (csn_compare((const CSN *)second_current_value_vucsn, (const CSN *)current_value_vucsn) < 0) {
+ /*
+ * The second value is older but was distinguished at the time the current value was added
+ * then the second value should become current
*/
- /* just remove the deleted value */
- entry_deleted_value_to_zapped_value(a, pending_value);
- /* move the attribute to the present attributes list */
- entry_deleted_attribute_to_present_attribute(e, a);
- pending_value = NULL;
- attr_set_deletion_csn(a, NULL);
- return; /* we are done - we are keeping the present value */
- } else if (new_value == NULL) {
- /* check if the pending value should become the current value */
- if (pending_value != NULL) {
- if (!value_distinguished_at_csn(e, a, current_value, pending_value_vucsn)) {
- /* attribute.current_value = attribute.pending_value; */
- /* attribute.pending_value = NULL; */
- entry_present_value_to_zapped_value(a, current_value);
- entry_deleted_value_to_present_value(a, pending_value);
- current_value = pending_value;
- pending_value = NULL;
- current_value_vucsn = pending_value_vucsn;
- pending_value_vucsn = NULL;
- }
+ if (value_distinguished_at_csn(e, a, second_current_value, (const CSN *)current_value_vucsn)) {
+ value_to_zap = current_value;
+ } else {
+ /* The second value being not distinguished, zap it as it is a single valued attribute */
+ value_to_zap = second_current_value;
}
- /* check if the current value should be deleted */
- if (current_value != NULL) {
- if (csn_compare(adcsn, current_value_vucsn) > 0) /* check if the attribute was deleted after the value was last updated */
- {
- if (!value_distinguished_at_csn(e, a, current_value, current_value_vucsn)) {
- entry_present_value_to_zapped_value(a, current_value);
- current_value = NULL;
- current_value_vucsn = NULL;
- }
- }
+
+ } else {
+ /* Here the current_value is older than the second_current_value */
+ if (value_distinguished_at_csn(e, a, current_value, (const CSN *)second_current_value_vucsn)) {
+ /* current_value was distinguished at the time the second value was added
+ * then the current_value should become the current */
+ value_to_zap = second_current_value;
+ } else {
+ value_to_zap = current_value;
}
- } else /* addition of a new value */
- {
- const CSN *new_value_vucsn = value_get_csn(new_value, CSN_TYPE_VALUE_UPDATED);
- if (csn_compare(new_value_vucsn, current_value_vucsn) < 0) {
- /*
- * if the new value was distinguished at the time the current value was added
- * then the new value should become current
+ }
+ entry_present_value_to_zapped_value(a, value_to_zap);
+
+
+
+}
+
+/* This routine applies for single valued attribute.
+ * It checks if the deleted value is more recent than
+ * the present one. If it is, it resurect the deleted value
+ *
+ * This function leaves untouch the adcsn
+ */
+static void
+resolve_single_valued_check_restore_deleted_value(Slapi_Entry *e, Slapi_Attr *a)
+{
+ Slapi_Value *deleted_value = NULL;
+ Slapi_Value *current_value = NULL;
+
+ /* Retrieve the deleted and current value */
+ deleted_value = attr_most_recent_deleted_value(a);
+ if (deleted_value == NULL) {
+ return;
+ }
+ slapi_attr_first_value(a, ¤t_value);
+
+ if (current_value == NULL) {
+ /* An attribute needs a present value */
+ entry_deleted_value_to_present_value(a, deleted_value);
+ } else {
+ CSN *current_value_vucsn;
+ CSN *deleted_value_vucsn;
+ CSN *deleted_value_vdcsn;
+
+ deleted_value_vucsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_UPDATED);
+ deleted_value_vdcsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_DELETED);
+ current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
+ if (deleted_value_vucsn &&
+ !value_distinguished_at_csn(e, a, current_value, (const CSN *)deleted_value_vucsn) &&
+ (csn_compare((const CSN *)current_value_vucsn, (const CSN *)deleted_value_vucsn) < 0) &&
+ (csn_compare((const CSN *)deleted_value_vdcsn, (const CSN *)current_value_vucsn) < 0)) {
+ /* the condition to resurrect the deleted value is
+ * - it is more recent than the current value
+ * - its value was deleted before the current value
+ * - the current value is not distinguished
*/
- if (value_distinguished_at_csn(e, a, new_value, current_value_vucsn)) {
- /* attribute.pending_value = attribute.current_value */
- /* attribute.current_value = new_value */
- if (pending_value == NULL) {
- entry_present_value_to_deleted_value(a, current_value);
- } else {
- entry_present_value_to_zapped_value(a, current_value);
- }
- pending_value = current_value;
- current_value = new_value;
- new_value = NULL;
- pending_value_vucsn = current_value_vucsn;
- current_value_vucsn = new_value_vucsn;
- } else {
- /* new_value= NULL */
- entry_present_value_to_zapped_value(a, new_value);
- new_value = NULL;
- }
- } else /* new value is after the current value */
- {
- if (!value_distinguished_at_csn(e, a, current_value, new_value_vucsn)) {
- /* attribute.current_value = new_value */
- entry_present_value_to_zapped_value(a, current_value);
- current_value = new_value;
- new_value = NULL;
- current_value_vucsn = new_value_vucsn;
- } else /* value is distinguished - check if we should replace the current pending value */
- {
- if (csn_compare(new_value_vucsn, pending_value_vucsn) > 0) {
- /* attribute.pending_value = new_value */
- entry_deleted_value_to_zapped_value(a, pending_value);
- entry_present_value_to_deleted_value(a, new_value);
- pending_value = new_value;
- new_value = NULL;
- pending_value_vucsn = new_value_vucsn;
- }
- }
+ entry_present_value_to_zapped_value(a, current_value);
+ entry_deleted_value_to_present_value(a, deleted_value);
}
}
+}
+/* This function deals with single valued attribute
+ * It zap the current value if the adcsn is more recent and the value is not distinguished
+ */
+static void
+resolve_single_valued_zap_current(Slapi_Entry *e, Slapi_Attr *a)
+{
+ Slapi_Value *current_value = NULL;
+ CSN *current_value_vucsn;
+ CSN *adcsn;
- /*
- * This call ensures that the attribute does not have a pending_value
- * or a deletion_csn that is earlier than the current_value.
+ /* check if the current value should be deleted because
+ * older than adcsn and not distinguished
*/
- /* purge_attribute_state_single_valued */
- if ((pending_value != NULL && (csn_compare(adcsn, pending_value_vucsn) < 0)) ||
- (pending_value == NULL && (csn_compare(adcsn, current_value_vucsn) < 0))) {
+ slapi_attr_first_value(a, ¤t_value);
+ current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
+ adcsn = attr_get_deletion_csn(a);
+ if (current_value != NULL) {
+ if (csn_compare((const CSN *)adcsn, (const CSN *) current_value_vucsn) > 0) {
+ /* the attribute was deleted after the value was last updated */
+ if (!value_distinguished_at_csn(e, a, current_value, (const CSN *) current_value_vucsn)) {
+ entry_present_value_to_zapped_value(a, current_value);
+ }
+ }
+ }
+}
+/* This function deals with single valued attribute
+ * It reset the adcsn if
+ * - there is no deleted value and current value is more recent than the adcsn
+ * - there is a deleted value and it is more recent than the adcsn
+ */
+static void
+resolve_single_valued_set_adcsn(Slapi_Attr *a)
+{
+ Slapi_Value *deleted_value = NULL;
+ Slapi_Value *current_value = NULL;
+ CSN *current_value_vucsn;
+ CSN *deleted_value_vucsn;
+ CSN *adcsn;
+
+ slapi_attr_first_value(a, ¤t_value);
+ current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
+ deleted_value = attr_most_recent_deleted_value(a);
+ deleted_value_vucsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_UPDATED);
+ adcsn = attr_get_deletion_csn(a);
+ if ((deleted_value != NULL && (csn_compare(adcsn, (const CSN *) deleted_value_vucsn) < 0)) ||
+ (deleted_value == NULL && (csn_compare(adcsn, (const CSN *) current_value_vucsn) < 0))) {
attr_set_deletion_csn(a, NULL);
- adcsn = NULL;
}
+}
+/* This function deals with single valued attribute
+ * It checks if the deleted value worth to be kept
+ *
+ * deleted value is zapped if
+ * - it is the result of MOD_REPL that is older than current value
+ * - It is the result of MOD_DEL_<value> that is belong to the same operation that set the current value
+ */
+static void
+resolve_single_valued_zap_deleted(Slapi_Attr *a)
+{
+ Slapi_Value *deleted_value = NULL;
+ Slapi_Value *current_value = NULL;
+ CSN *current_value_vucsn;
+ CSN *deleted_value_vucsn;
+ CSN *deleted_value_vdcsn;
+ CSN *deleted_value_csn;
+ PRBool deleted_on_mod_del = PR_FALSE; /* flag if a value was deleted specifically */
+
+ /* Now determine if the deleted value worth to be kept */
+ slapi_attr_first_value(a, ¤t_value);
+ current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
+
+ deleted_value = attr_most_recent_deleted_value(a);
+ deleted_value_vucsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_UPDATED);
+ deleted_value_vdcsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_DELETED);
+
+ /* get the appropriate csn to take into consideration: either from MOD_REPL or from MOD_DEL_specific */
+ if (csn_compare((const CSN *) deleted_value_vdcsn, (const CSN *) deleted_value_vucsn) <= 0) {
+ deleted_value_csn = deleted_value_vucsn;
+ } else {
+ deleted_value_csn = deleted_value_vdcsn;
+ if (0 == csn_compare_ext((const CSN *) current_value_vucsn, (const CSN *) deleted_value_vdcsn, CSN_COMPARE_SKIP_SUBSEQ)) {
+ /* the deleted value was specifically delete in the same operation that set the current value */
+ deleted_on_mod_del = PR_TRUE;
+ }
+ }
+ if ((csn_compare((const CSN *) deleted_value_csn, (const CSN *) current_value_vucsn) < 0) || deleted_on_mod_del) {
+ entry_deleted_value_to_zapped_value(a, deleted_value);
+ }
+}
+
+/* This function deals with single valued attribute
+ * It does a set of cleanup in the current/deleted values in order
+ * to conform the schema, take care of distinguished values and only preserve the
+ * values that worth to be kept.
+ */
+static void
+resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribute_state)
+{
+ int32_t nbval, i;
+ Slapi_Value *current_value = NULL;
+
+ /* retrieve the current value(s) */
+ slapi_attr_get_numvalues(a, &nbval);
+ i = slapi_attr_first_value(a, ¤t_value);
+
+ /* If there are several values, first determine which value will be the current (present) one */
+ if (nbval > 1) {
+ /* There are several values for a single valued attribute, keep the most recent one */
+ if (i == -1) {
+ slapi_log_err(SLAPI_LOG_ERR, "resolve_attribute_state_single_valued", "Unexpected state of %s that contains more than one value but can not read the second\n", a->a_type);
+ } else {
+ Slapi_Value *second_current_value = NULL;
+
+ slapi_attr_next_value(a, i, &second_current_value);
+ resolve_single_valued_two_values(e, a, attribute_state, current_value, second_current_value);
+ }
+ }
+ /* There is only one current value (present value) */
+
+ /* Now determine if the deleted value needs to replace the current value */
+ resolve_single_valued_check_restore_deleted_value(e, a);
+
+ /* Now determine if the deleted value worth to be kept (vs. current value) */
+ resolve_single_valued_zap_deleted(a);
+
+ /* Now determine if the current value worth to be kept (vs. adcsn) */
+ resolve_single_valued_zap_current(e, a);
+
+ /* Now set the adcsn */
+ resolve_single_valued_set_adcsn(a);
- /* set attribute state */
+ /* set the attribute in the correct list in the entry: present or deleted */
+ slapi_attr_first_value(a, ¤t_value);
if (current_value == NULL) {
if (attribute_state == ATTRIBUTE_PRESENT) {
entry_present_attribute_to_deleted_attribute(e, a);
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years, 2 months
[389-ds-base] branch 389-ds-base-1.4.0 updated: Ticket 49658 - In replicated topology a single-valued attribute can diverge
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
tbordaz pushed a commit to branch 389-ds-base-1.4.0
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.4.0 by this push:
new 70cac1b Ticket 49658 - In replicated topology a single-valued attribute can diverge
70cac1b is described below
commit 70cac1b11a22103ca29fa3f8382b882b3bcbae7e
Author: Thierry Bordaz <tbordaz(a)redhat.com>
AuthorDate: Tue May 15 16:45:56 2018 +0200
Ticket 49658 - In replicated topology a single-valued attribute can diverge
Bug Description:
When deleting a specific value of a single valued attribute,
the deleted value can be erronously resurrected.
Fix Description:
This second fix is a rewrite of entry state resolution.
The original function (resolve_attribute_state_single_valued) implemented
a main algorythm but it was heavily merged with resolution of specific cases.
It was too difficult to make the function understandable and preserving
the handling of the specific cases.
The risk of that rewrite fix is that I can not guarantee it fully covers
the set of specific cases
https://pagure.io/389-ds-base/issue/49658
Reviewed by: William Brown (Thanks !!)
Platforms tested: F27
Flag Day: no
Doc impact: no
---
dirsrvtests/tests/tickets/ticket49658_test.py | 4264 +++++++++++++++++++++++++
ldap/servers/slapd/entrywsi.c | 404 ++-
2 files changed, 4521 insertions(+), 147 deletions(-)
diff --git a/dirsrvtests/tests/tickets/ticket49658_test.py b/dirsrvtests/tests/tickets/ticket49658_test.py
new file mode 100644
index 0000000..53522df
--- /dev/null
+++ b/dirsrvtests/tests/tickets/ticket49658_test.py
@@ -0,0 +1,4264 @@
+import logging
+import pytest
+import os
+import ldap
+import time
+import sys
+print(sys.path)
+from lib389 import Entry
+from lib389._constants import DEFAULT_SUFFIX
+from lib389.idm.user import UserAccounts, TEST_USER_PROPERTIES
+from lib389.topologies import topology_m3 as topo
+
+DEBUGGING = os.getenv("DEBUGGING", default=False)
+if DEBUGGING:
+ logging.getLogger(__name__).setLevel(logging.DEBUG)
+else:
+ logging.getLogger(__name__).setLevel(logging.INFO)
+log = logging.getLogger(__name__)
+
+
+MAX_EMPLOYEENUMBER_USER = 20
+MAX_STANDARD_USER = 100
+MAX_USER = MAX_STANDARD_USER + MAX_EMPLOYEENUMBER_USER
+EMPLOYEENUMBER_RDN_START = 0
+
+USER_UID='user_'
+BASE_DISTINGUISHED = 'ou=distinguished,ou=people,%s' % (DEFAULT_SUFFIX)
+BASE_REGULAR = 'ou=regular,ou=people,%s' % (DEFAULT_SUFFIX)
+
+def _user_get_dn(no):
+ uid = '%s%d' % (USER_UID, no)
+ dn = 'uid=%s,%s' % (uid, BASE_REGULAR)
+ return (uid, dn)
+
+def add_user(server, no, init_val):
+ (uid, dn) = _user_get_dn(no)
+ log.fatal('Adding user (%s): ' % dn)
+ server.add_s(Entry((dn, {'objectclass': ['top', 'person', 'organizationalPerson', 'inetOrgPerson'],
+ 'uid': [uid],
+ 'sn' : [uid],
+ 'cn' : [uid],
+ 'employeeNumber': init_val})))
+ return dn
+
+def _employeenumber_user_get_dn(no):
+ employeeNumber = str(no)
+ dn = 'employeeNumber=%s,%s' % (employeeNumber, BASE_DISTINGUISHED)
+ return (employeeNumber, dn)
+
+def add_employeenumber_user(server, no):
+ (uid, dn) = _employeenumber_user_get_dn(EMPLOYEENUMBER_RDN_START + no)
+ log.fatal('Adding user (%s): ' % dn)
+ server.add_s(Entry((dn, {'objectclass': ['top', 'person', 'organizationalPerson', 'inetOrgPerson'],
+ 'uid': [uid],
+ 'sn' : [uid],
+ 'cn' : [uid],
+ 'employeeNumber': str(EMPLOYEENUMBER_RDN_START + no)})))
+ return dn
+
+def save_stuff():
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_11 = '11'.encode()
+ value_1000 = '1000'.encode()
+ value_13 = '13'.encode()
+ value_14 = '14'.encode()
+
+ # Step 2
+ test_user_dn= add_user(M3, 0, value_11)
+ log.info('Adding %s on M3' % test_user_dn)
+ M3.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_11), (ldap.MOD_ADD, 'employeeNumber', value_1000)])
+ ents = M3.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == 1
+
+
+ # Step 3
+ # Check the entry is replicated on M1
+ for j in range(30):
+ try:
+ ent = M1.getEntry(test_user_dn, ldap.SCOPE_BASE,)
+ if not ent.hasAttr('employeeNumber'):
+ # wait for the MOD
+ log.info('M1 waiting for employeeNumber')
+ time.sleep(1)
+ continue;
+ break;
+ except ldap.NO_SUCH_OBJECT:
+ time.sleep(1)
+ pass
+ time.sleep(1)
+ ents = M1.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == 1
+
+ # Check the entry is replicated on M2
+ for j in range(30):
+ try:
+ ent = M2.getEntry(test_user_dn, ldap.SCOPE_BASE,)
+ if not ent.hasAttr('employeeNumber'):
+ # wait for the MOD
+ log.info('M2 waiting for employeeNumber')
+ time.sleep(1)
+ continue;
+
+ break;
+ except ldap.NO_SUCH_OBJECT:
+ time.sleep(1)
+ pass
+ time.sleep(1)
+ ents = M2.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == 1
+
+def test_ticket49658_init(topo):
+ """Specify a test case purpose or name here
+
+ :id: 0
+ :setup: 3 Master Instances
+ :steps:
+ 1. Create 3 suppliers
+ 2. Create on M3 MAX_USER test entries having a single-value attribute employeeNumber=11
+ and update it MOD_DEL 11 + MOD_ADD 1000
+ 3. Check they are replicated on M1 and M2
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_11 = '11'.encode()
+ value_1000 = '1000'.encode()
+
+ # Step 2
+ M3.add_s(Entry((BASE_DISTINGUISHED, {'objectclass': ['top', 'organizationalUnit'],
+ 'ou': ['distinguished']})))
+ for i in range(MAX_EMPLOYEENUMBER_USER):
+ test_user_dn= add_employeenumber_user(M3, i)
+ log.info('Adding %s on M3' % test_user_dn)
+ ents = M3.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == (i + 1)
+
+ M3.add_s(Entry((BASE_REGULAR, {'objectclass': ['top', 'organizationalUnit'],
+ 'ou': ['regular']})))
+ for i in range(MAX_STANDARD_USER):
+ test_user_dn= add_user(M3, i, value_11)
+ log.info('Adding %s on M3' % test_user_dn)
+ M3.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_11), (ldap.MOD_ADD, 'employeeNumber', value_1000)])
+ ents = M3.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == (MAX_EMPLOYEENUMBER_USER + i + 1)
+
+
+ # Step 3
+ # Check the last entry is replicated on M1
+ (uid, test_user_dn) = _user_get_dn(MAX_STANDARD_USER - 1)
+ for j in range(30):
+ try:
+ ent = M1.getEntry(test_user_dn, ldap.SCOPE_BASE,)
+ if not ent.hasAttr('employeeNumber'):
+ # wait for the MOD
+ log.info('M1 waiting for employeeNumber')
+ time.sleep(1)
+ continue;
+ break;
+ except ldap.NO_SUCH_OBJECT:
+ time.sleep(1)
+ pass
+ time.sleep(1)
+ ents = M1.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_USER
+
+ # Check the last entry is replicated on M2
+ for j in range(30):
+ try:
+ ent = M2.getEntry(test_user_dn, ldap.SCOPE_BASE,)
+ if not ent.hasAttr('employeeNumber'):
+ # wait for the MOD
+ log.info('M2 waiting for employeeNumber')
+ time.sleep(1)
+ continue;
+
+ break;
+ except ldap.NO_SUCH_OBJECT:
+ time.sleep(1)
+ pass
+ time.sleep(1)
+ ents = M2.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_USER
+
+def test_ticket49658_0(topo):
+ """Do MOD(DEL+ADD) and replicate MOST RECENT first
+ M1: MOD(DEL+ADD) -> V1
+ M2: MOD(DEL+ADD) -> V1
+ expected: V1
+
+ :id: 0
+ :setup: 3 Master Instances
+ 1. using user_0 where employNumber=1000
+ :steps:
+ 1. Create 3 suppliers
+ 2. Isolate M1 and M2 by pausing the replication agreements
+ 3. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 4. On M2 do MOD_DEL 1000 + MOD_ADD_13
+ 5. Enable replication agreement M2 -> M3, so that update step 6 is replicated first
+ 6. Enable replication agreement M1 -> M3, so that update step 5 is replicated second
+ 7. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'.encode()
+ last = '0'
+ value_end = last.encode()
+ theFilter = '(employeeNumber=%s)' % last
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 2
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 3
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ M1.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_1000), (ldap.MOD_ADD, 'employeeNumber', value_end)])
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 4
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M2.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_1000), (ldap.MOD_ADD, 'employeeNumber', value_end)])
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+def test_ticket49658_1(topo):
+ """Do MOD(DEL+ADD) and replicate OLDEST first
+ M2: MOD(DEL+ADD) -> V1
+ M1: MOD(DEL+ADD) -> V1
+ expected: V1
+
+ :id: 1
+ :setup: 3 Master Instances
+ 1. using user_1 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M2 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'.encode()
+ last = '1'
+ value_end = last.encode()
+ theFilter = '(employeeNumber=%s)' % last
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(1))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M2.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_1000), (ldap.MOD_ADD, 'employeeNumber', value_end)])
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M1.modify_s(test_user_dn, [(ldap.MOD_DELETE, 'employeeNumber', value_1000), (ldap.MOD_ADD, 'employeeNumber', value_end)])
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+def test_ticket49658_2(topo):
+ """Do MOD(ADD+DEL) and replicate OLDEST first
+ M2: MOD(ADD+DEL) -> V1
+ M1: MOD(ADD+DEL) -> V1
+ expected: V1
+
+ :id: 2
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M2 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'.encode()
+ last = '2'
+ value_end = last.encode()
+ theFilter = '(employeeNumber=%s)' % last
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M2.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end),(ldap.MOD_DELETE, 'employeeNumber', value_1000)])
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M1.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end), (ldap.MOD_DELETE, 'employeeNumber', value_1000)])
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+def test_ticket49658_3(topo):
+ """Do MOD(ADD+DEL) and replicate MOST RECENT first
+ M1: MOD(ADD+DEL) -> V1
+ M2: MOD(ADD+DEL) -> V1
+ expected: V1
+ :id: 3
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_DEL 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'.encode()
+ last = '3'
+ value_end = last.encode()
+ theFilter = '(employeeNumber=%s)' % last
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ M1.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end),(ldap.MOD_DELETE, 'employeeNumber', value_1000)])
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M2.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end), (ldap.MOD_DELETE, 'employeeNumber', value_1000)])
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+def test_ticket49658_4(topo):
+ """Do MOD(ADD+DEL) MOD(REPL) and replicate MOST RECENT first
+ M1: MOD(ADD+DEL) -> V1
+ M2: MOD(REPL) -> V1
+ expected: V1
+
+ :id: 4
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'.encode()
+ last = '4'
+ value_end = last.encode()
+ theFilter = '(employeeNumber=%s)' % last
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ M1.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end),(ldap.MOD_DELETE, 'employeeNumber', value_1000)])
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M2.modify_s(test_user_dn, [(ldap.MOD_REPLACE, 'employeeNumber', value_end)])
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+def test_ticket49658_5(topo):
+ """Do MOD(REPL) MOD(ADD+DEL) and replicate MOST RECENT first
+ M1: MOD(REPL) -> V1
+ M2: MOD(ADD+DEL) -> V1
+ expected: V1
+ :id: 5
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'.encode()
+ last = '5'
+ value_end = last.encode()
+ theFilter = '(employeeNumber=%s)' % last
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ M1.modify_s(test_user_dn, [(ldap.MOD_REPLACE, 'employeeNumber', value_end)])
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ M2.modify_s(test_user_dn, [(ldap.MOD_ADD, 'employeeNumber', value_end),(ldap.MOD_DELETE, 'employeeNumber', value_1000)])
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, theFilter)
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), value_end))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == value_end
+
+def test_ticket49658_6(topo):
+ """Do
+ M1: MOD(REPL) -> V1
+ M2: MOD(ADD+DEL) -> V2
+ expected: V2
+
+ :id: 6
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '6'
+ value_S1 = '6.1'
+ value_S2 = '6.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_ADD, 'employeeNumber', value_S2.encode()),(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode())],
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_7(topo):
+ """Do
+ M1: MOD(ADD+DEL) -> V1
+ M2: MOD(REPL) -> V2
+ expected: V2
+
+ :id: 7
+ :setup: 3 Master Instances
+ :steps:
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '7'
+ value_S1 = '7.1'
+ value_S2 = '7.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_ADD, 'employeeNumber', value_S1.encode()),(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_8(topo):
+ """Do
+ M1: MOD(DEL+ADD) -> V1
+ M2: MOD(REPL) -> V2
+ expected: V2
+
+ :id: 8
+ :setup: 3 Master Instances
+ :steps:
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '8'
+ value_S1 = '8.1'
+ value_S2 = '8.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+def test_ticket49658_9(topo):
+ """Do
+ M1: MOD(REPL) -> V1
+ M2: MOD(DEL+ADD) -> V2
+ expected: V2
+
+ :id: 9
+ :setup: 3 Master Instances
+ :steps:
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '9'
+ value_S1 = '9.1'
+ value_S2 = '9.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+
+def test_ticket49658_10(topo):
+ """Do
+ M1: MOD(REPL) -> V1
+ M2: MOD(REPL) -> V2
+ expected: V2
+
+ :id: 10
+ :setup: 3 Master Instances
+ :steps:
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '10'
+ value_S1 = '10.1'
+ value_S2 = '10.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+
+def test_ticket49658_11(topo):
+ """Do
+ M2: MOD(REPL) -> V2
+ M1: MOD(REPL) -> V1
+ expected: V1
+
+ :id: 11
+ :setup: 3 Master Instances
+ :steps:
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '11'
+ value_S1 = '11.1'
+ value_S2 = '11.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_12(topo):
+ """Do
+ M2: MOD(ADD+DEL) -> V2
+ M1: MOD(REPL) -> V1
+ expected: V1
+
+ :id: 12
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '12'
+ value_S1 = '12.1'
+ value_S2 = '12.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_ADD, 'employeeNumber', value_S2.encode()),(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode())],
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_13(topo):
+ """Do
+ M2: MOD(DEL+ADD) -> V2
+ M1: MOD(REPL) -> V1
+ expected: V1
+
+ :id: 13
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '13'
+ value_S1 = '13.1'
+ value_S2 = '13.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+def test_ticket49658_14(topo):
+ """Do
+ M2: MOD(DEL+ADD) -> V2
+ M1: MOD(DEL+ADD) -> V1
+ expected: V1
+
+ :id: 14
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '14'
+ value_S1 = '14.1'
+ value_S2 = '14.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_15(topo):
+ """Do
+ M2: MOD(ADD+DEL) -> V2
+ M1: MOD(DEL+ADD) -> V1
+ expected: V1
+
+ :id: 15
+ :setup: 3 Master Instances
+ 1. using user_2 where employNumber=1000
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do MOD_DEL 1000 + MOD_ADD_13
+ 3. On M2 do MOD_REPL _13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_1000 = '1000'
+ last = '15'
+ value_S1 = '15.1'
+ value_S2 = '15.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_ADD, 'employeeNumber', value_S2.encode()),(ldap.MOD_DELETE, 'employeeNumber', value_1000.encode())],
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S2"].modify_s(test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S1"].modify_s(test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ #time.sleep(60)
+ # Step 7
+ # Renable M2 before M1 so that on M3, the most recent update is replicated before
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ # Step 8
+ # Renable M1 so that on M3 oldest update is now replicated
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_STANDARD_USER
+ ents = M3.search_s(BASE_REGULAR, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+def _resume_ra_M1_then_M2(M1, M2, M3):
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+
+ time.sleep(4)
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+ time.sleep(4)
+
+def _resume_ra_M2_then_M1(M1, M2, M3):
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ for ra in agreement_m2_m1, agreement_m2_m3:
+ M2.agreement.resume(ra[0].dn)
+
+ time.sleep(4)
+ for ra in agreement_m1_m2, agreement_m1_m3:
+ M1.agreement.resume(ra[0].dn)
+ time.sleep(4)
+
+
+def test_ticket49658_16(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V1
+ expected: V1
+ resume order: M2, M1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '1'
+ last = '1'
+ value_S1 = '1.1'
+ value_S2 = value_S1
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S2_MODRDN": value_S2,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+def test_ticket49658_17(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ expected: V2
+ resume order: M2 then M1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '2'
+ last = '2'
+ value_S1 = '2.1'
+ value_S2 = '2.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_18(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ expected: V2
+ resume order: M1 then M2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '2'
+ last = '3'
+ value_S1 = '3.1'
+ value_S2 = '3.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_19(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ Replicate order: M2 then M1
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '3'
+ last = '4'
+ value_S1 = '4.1'
+ value_S2 = '4.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_20(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ Replicate order: M1 then M2
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '3'
+ last = '5'
+ value_S1 = '5.1'
+ value_S2 = '5.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_21(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(DEL/ADD) -> V1
+ Replicate order: M2 then M1
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '3'
+ last = '6'
+ value_S1 = '6.1'
+ value_S2 = '6.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_22(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(DEL/ADD) -> V1
+ Replicate: M1 then M2
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '3'
+ last = '7'
+ value_S1 = '7.1'
+ value_S2 = '7.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_23(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MOD(REPL) -> V2
+ Replicate order: M2 then M1
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '8'
+ value_S1 = '8.1'
+ value_S2 = '8.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_24(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MOD(REPL) -> V2
+ Replicate order: M1 then M2
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '9'
+ value_S1 = '9.1'
+ value_S2 = '9.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_25(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MOD(DEL/ADD) -> V2
+ Replicate order: M1 then M2
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '10'
+ value_S1 = '10.1'
+ value_S2 = '10.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S2.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_26(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MOD(DEL/ADD) -> V2
+ Replicate order: M2 then M1
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '11'
+ value_S1 = '11.1'
+ value_S2 = '11.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S2.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_27(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(DEL/ADD) -> V1
+ M2: MOD(REPL) -> V2
+ Replicate order: M1 then M2
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '12'
+ value_S1 = '12.1'
+ value_S2 = '12.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_28(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(DEL/ADD) -> V1
+ M2: MOD(REPL) -> V2
+ Replicate order: M2 then M1
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '13'
+ value_S1 = '13.1'
+ value_S2 = '13.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+def test_ticket49658_29(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(DEL/ADD) -> V1
+ M2: MOD(DEL/ADD) -> V2
+ Replicate order: M1 then M2
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '14'
+ value_S1 = '14.1'
+ value_S2 = '14.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S2.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_30(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(DEL/ADD) -> V1
+ M2: MOD(DEL/ADD) -> V2
+ Replicate order: M2 then M1
+ expected: V2
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '15'
+ value_S1 = '15.1'
+ value_S2 = '15.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S1.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_DELETE, 'employeeNumber', value_S2.encode()),(ldap.MOD_ADD, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN": value_S2,
+ "expected": value_S2}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_31(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MOD(REPL) -> V2
+ M2: MODRDN -> V1
+ Replicate order: M2 then M1
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '16'
+ value_S1 = '16.1'
+ value_S2 = '16.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN_1": value_S2,
+ "S2_MODRDN_2": value_S1,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_1"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_1"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN_1"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ description["S2"].rename_s(new_test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_2"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_2"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+
+def test_ticket49658_32(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MOD(REPL) -> V2
+ M2: MODRDN -> V1
+ Replicate order: M1 then M2
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '17'
+ value_S1 = '17.1'
+ value_S2 = '17.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S2.encode())],
+ "S2_MODRDN_1": value_S2,
+ "S2_MODRDN_2": value_S1,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_1"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_1"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN_1"])
+ description["S2"].modify_s(new_test_user_dn, description["S2_MOD"])
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S2)
+ assert len(ents) == 1
+
+ description["S2"].rename_s(new_test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_2"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_2"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_33(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MODRDN -> V1
+ Replicate order: M2 then M1
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '18'
+ value_S1 = '18.1'
+ value_S2 = '18.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MODRDN_1": value_S2,
+ "S2_MODRDN_2": value_S1,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_1"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_1"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN_1"])
+ description["S2"].rename_s(new_test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_2"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_2"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ _resume_ra_M2_then_M1(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+def test_ticket49658_34(topo):
+ """Do
+ M1: MODRDN -> V1
+ M2: MODRDN -> V2
+ M1: MOD(REPL) -> V1
+ M2: MODRDN -> V1
+ Replicate order: M1 then M2
+ expected: V1
+
+ :id: 16
+ :setup: 3 Master Instances
+ 1. Use employeenumber=1000,ou=distinguished,ou=people,<suffix>
+ :steps:
+ 1. Isolate M1 and M2 by pausing the replication agreements
+ 2. On M1 do DEL+ADD 1000 + MOD_ADD_13
+ 3. On M2 do DEL+ADD 1000 + MOD_ADD_13
+ 4. Enable replication agreement M2 -> M3, so that update step 2 is replicated first
+ 5. Enable replication agreement M1 -> M3, so that update step 3 is replicated second
+ 6. Check that the employeeNumber is 13 on all servers
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+ M1 = topo.ms["master1"]
+ M2 = topo.ms["master2"]
+ M3 = topo.ms["master3"]
+ value_init = '7'
+ last = '19'
+ value_S1 = '19.1'
+ value_S2 = '19.2'
+
+ description = {
+ "S1": M1,
+ "S2": M2,
+ "S1_MODRDN": value_S1,
+ "S1_MOD": [(ldap.MOD_REPLACE, 'employeeNumber', value_S1.encode())],
+ "S2_MODRDN_1": value_S2,
+ "S2_MODRDN_2": value_S1,
+ "expected": value_S1}
+
+ # This test takes the user_1
+ (uid, test_user_dn) = _employeenumber_user_get_dn(int(last))
+
+ #
+ # Step 4
+ #
+ # disable all RA from M1 and M2
+ # only M3 can replicate the update
+ #
+ agreement_m1_m2 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M2.host, consumer_port=M2.port)
+ agreement_m1_m3 = M1.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+ agreement_m2_m1 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M1.host, consumer_port=M1.port)
+ agreement_m2_m3 = M2.agreement.list(suffix=DEFAULT_SUFFIX, consumer_host=M3.host, consumer_port=M3.port)
+
+ M1.agreement.pause(agreement_m1_m2[0].dn)
+ M1.agreement.pause(agreement_m1_m3[0].dn)
+ M2.agreement.pause(agreement_m2_m1[0].dn)
+ M2.agreement.pause(agreement_m2_m3[0].dn)
+
+ # Step 5
+ # Oldest update
+ # check that the entry on M1 contains employeeNumber=<value_end>
+ description["S1"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S1_MODRDN"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S1_MODRDN"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ # Step 6
+ # More recent update
+ # check that the entry on M2 contains employeeNumber=<value_end>
+ description["S2"].rename_s(test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_1"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_1"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S1_MODRDN"])
+ description["S1"].modify_s(new_test_user_dn, description["S1_MOD"])
+ ents = description["S1"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % value_S1)
+ assert len(ents) == 1
+ time.sleep(1)
+
+ (no, new_test_user_dn) = _employeenumber_user_get_dn(description["S2_MODRDN_1"])
+ description["S2"].rename_s(new_test_user_dn, 'employeeNumber=%s' % description["S2_MODRDN_2"], newsuperior=BASE_DISTINGUISHED, delold=1)
+ ents = description["S2"].search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["S2_MODRDN_2"])
+ assert len(ents) == 1
+ time.sleep(1)
+
+ _resume_ra_M1_then_M2(M1, M2, M3)
+
+ #time.sleep(3600)
+ # Step 9
+ # Check that M1 still contains employeeNumber=<value_end>
+ ents = M1.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M1 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M2 still contains employeeNumber=<value_end>
+ ents = M2.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M2 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+
+ # Check that M3 still contain employeeNumber and it contains employeeNumber=<value_end>
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=*)')
+ assert len(ents) == MAX_EMPLOYEENUMBER_USER
+ ents = M3.search_s(BASE_DISTINGUISHED, ldap.SCOPE_SUBTREE, '(employeeNumber=%s)' % description["expected"])
+ log.info('Search M3 employeeNumber=%s (vs. %s)' % (ents[0].getValue('employeeNumber'), description["expected"]))
+ assert len(ents) == 1
+ assert ents[0].hasAttr('employeeNumber') and ents[0].getValue('employeeNumber') == description["expected"].encode()
+if __name__ == '__main__':
+ # Run isolated
+ # -s for DEBUG mode
+ CURRENT_FILE = os.path.realpath(__file__)
+ pytest.main(["-s", CURRENT_FILE])
+
diff --git a/ldap/servers/slapd/entrywsi.c b/ldap/servers/slapd/entrywsi.c
index 58f7870..080eb15 100644
--- a/ldap/servers/slapd/entrywsi.c
+++ b/ldap/servers/slapd/entrywsi.c
@@ -359,6 +359,13 @@ entry_add_present_attribute_wsi(Slapi_Entry *e, Slapi_Attr *a)
* Preserves LDAP Information Model constraints,
* returning an LDAP result code.
*/
+static void entry_dump_stateinfo(char *msg, Slapi_Entry* e);
+static Slapi_Value *attr_most_recent_deleted_value(Slapi_Attr *a);
+static void resolve_single_valued_two_values(Slapi_Entry *e, Slapi_Attr *a, int attribute_state, Slapi_Value *current_value, Slapi_Value *second_current_value);
+static void resolve_single_valued_check_restore_deleted_value(Slapi_Entry *e, Slapi_Attr *a);
+static void resolve_single_valued_zap_current(Slapi_Entry *e, Slapi_Attr *a);
+static void resolve_single_valued_set_adcsn(Slapi_Attr *a);
+static void resolve_single_valued_zap_deleted(Slapi_Attr *a);
static void resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribute_state);
static void resolve_attribute_state_deleted_to_present(Slapi_Entry *e, Slapi_Attr *a, Slapi_Value **valuestoupdate);
static void resolve_attribute_state_present_to_deleted(Slapi_Entry *e, Slapi_Attr *a, Slapi_Value **valuestoupdate);
@@ -387,6 +394,20 @@ entry_add_present_values_wsi(Slapi_Entry *e, const char *type, struct berval **b
return retVal;
}
+/* Used for debug purpose, it dumps into the error log the
+ * entry with the replication stateinfo
+ */
+static void
+entry_dump_stateinfo(char *msg, Slapi_Entry* e)
+{
+ char *s;
+ int32_t len = 0;
+
+ s = slapi_entry2str_with_options(e, &len, SLAPI_DUMP_STATEINFO);
+ slapi_log_err(SLAPI_LOG_ERR, msg, "%s\n", s);
+ slapi_ch_free((void **)&s);
+}
+
static int
entry_add_present_values_wsi_single_valued(Slapi_Entry *e, const char *type, struct berval **bervals, const CSN *csn, int urp, long flags)
{
@@ -705,6 +726,10 @@ entry_delete_present_values_wsi_single_valued(Slapi_Entry *e, const char *type,
/* The attribute is single valued and the value was successful deleted */
/* but there could have been an add in the same operation, so double check */
if (valueset_isempty(&a->a_present_values)) {
+ /* A doubt here, a direct update deletes the last value
+ * of a single valued attribute. It will only contain deleted values.
+ * Why not setting the adcsn (attr_set_deletion_csn) ?
+ */
entry_present_attribute_to_deleted_attribute(e, a);
}
} else if (retVal != LDAP_SUCCESS) {
@@ -1229,169 +1254,254 @@ resolve_attribute_state_present_to_deleted(Slapi_Entry *e, Slapi_Attr *a, Slapi_
}
}
-static void
-resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribute_state)
+/* Retrieve from the deleted values the one that
+ * was the most recently deleted. Based on its vdcsn
+ */
+static Slapi_Value *
+attr_most_recent_deleted_value(Slapi_Attr *a)
{
- Slapi_Value *current_value = NULL;
- Slapi_Value *pending_value = NULL;
- Slapi_Value *new_value = NULL;
- const CSN *current_value_vucsn;
- const CSN *pending_value_vucsn;
- const CSN *pending_value_vdcsn;
- const CSN *adcsn;
+ Slapi_Value *v, *most_recent_v;
int i;
+ CSN *vdcsn, *most_recent_vdcsn;
- /*
- * this call makes sure that the attribute does not have a pending_value
- * or deletion_csn which is before the current_value.
- */
- i = slapi_attr_first_value(a, ¤t_value);
- if (i != -1) {
- slapi_attr_next_value(a, i, &new_value);
- }
- attr_first_deleted_value(a, &pending_value);
- /* purge_attribute_state_single_valued */
- adcsn = attr_get_deletion_csn(a);
- current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
- pending_value_vucsn = value_get_csn(pending_value, CSN_TYPE_VALUE_UPDATED);
- pending_value_vdcsn = value_get_csn(pending_value, CSN_TYPE_VALUE_DELETED);
- if ((pending_value != NULL && (csn_compare(adcsn, pending_value_vucsn) < 0)) ||
- (pending_value == NULL && (csn_compare(adcsn, current_value_vucsn) < 0))) {
- attr_set_deletion_csn(a, NULL);
- adcsn = NULL;
+ vdcsn = NULL;
+ most_recent_vdcsn = NULL;
+ i = attr_first_deleted_value(a, &v);
+ most_recent_v = v;
+
+ while (i != -1) {
+ vdcsn = value_get_csn(v, CSN_TYPE_VALUE_DELETED);
+
+ if (csn_compare((const CSN *)most_recent_vdcsn, (const CSN *)vdcsn) < 0) {
+ most_recent_v = v;
+ most_recent_vdcsn = vdcsn;
+ }
+ i = attr_next_deleted_value(a, i, &v);
}
+ return most_recent_v;
+}
- /* in the case of the following:
- * add: value2
- * delete: value1
- * we will have current_value with VUCSN CSN1
- * and pending_value with VDCSN CSN2
- * and new_value == NULL
- * current_value != pending_value
- * and
- * VUCSN == VDCSN (ignoring subseq)
- * even though value1.VDCSN > value2.VUCSN
- * value2 should still win because the value is _different_
- */
- if (current_value && pending_value && !new_value && !adcsn &&
- (0 != slapi_value_compare(a, current_value, pending_value)) &&
- (0 == csn_compare_ext(current_value_vucsn, pending_value_vdcsn, CSN_COMPARE_SKIP_SUBSEQ))) {
- /* just remove the deleted value */
- entry_deleted_value_to_zapped_value(a, pending_value);
- pending_value = NULL;
- } else if (current_value && pending_value && !new_value && adcsn &&
- (attribute_state == ATTRIBUTE_DELETED) &&
- current_value_vucsn && !pending_value_vucsn && pending_value_vdcsn &&
- (csn_compare(current_value_vucsn, pending_value_vdcsn) > 0) &&
- (csn_compare(adcsn, pending_value_vdcsn) == 0)) {
- /* in the case of the following:
- * beginning attr state is a deleted value
- * incoming operation is
- * add: newvalue
- * attribute_state is ATTRIBUTE_DELETED
- * so we have both a current_value and a pending_value
- * new_value is NULL
- * current_value_vucsn is CSN1
- * pending_value_vucsn is NULL
- * pending_value_vdcsn is CSN2
- * adcsn is CSN2 == pending_value_vdcsn
- * CSN1 > CSN2
- * since the pending_value is deleted, and the current_value has
- * a greater CSN, we should keep the current_value and zap
- * the pending_value
+/* This routine applies for single valued attribute.
+ * The attribute has two current values, it keeps the most recent one
+ * and zap the oldest
+ */
+static void
+resolve_single_valued_two_values(Slapi_Entry *e, Slapi_Attr *a, int attribute_state, Slapi_Value *current_value, Slapi_Value *second_current_value)
+{
+
+ CSN *current_value_vucsn;
+ CSN *second_current_value_vucsn;
+ Slapi_Value *value_to_zap;
+
+ current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
+ second_current_value_vucsn = value_get_csn(second_current_value, CSN_TYPE_VALUE_UPDATED);
+
+ /* First determine which present value will be zapped */
+ if (csn_compare((const CSN *)second_current_value_vucsn, (const CSN *)current_value_vucsn) < 0) {
+ /*
+ * The second value is older but was distinguished at the time the current value was added
+ * then the second value should become current
*/
- /* just remove the deleted value */
- entry_deleted_value_to_zapped_value(a, pending_value);
- /* move the attribute to the present attributes list */
- entry_deleted_attribute_to_present_attribute(e, a);
- pending_value = NULL;
- attr_set_deletion_csn(a, NULL);
- return; /* we are done - we are keeping the present value */
- } else if (new_value == NULL) {
- /* check if the pending value should become the current value */
- if (pending_value != NULL) {
- if (!value_distinguished_at_csn(e, a, current_value, pending_value_vucsn)) {
- /* attribute.current_value = attribute.pending_value; */
- /* attribute.pending_value = NULL; */
- entry_present_value_to_zapped_value(a, current_value);
- entry_deleted_value_to_present_value(a, pending_value);
- current_value = pending_value;
- pending_value = NULL;
- current_value_vucsn = pending_value_vucsn;
- pending_value_vucsn = NULL;
- }
+ if (value_distinguished_at_csn(e, a, second_current_value, (const CSN *)current_value_vucsn)) {
+ value_to_zap = current_value;
+ } else {
+ /* The second value being not distinguished, zap it as it is a single valued attribute */
+ value_to_zap = second_current_value;
}
- /* check if the current value should be deleted */
- if (current_value != NULL) {
- if (csn_compare(adcsn, current_value_vucsn) > 0) /* check if the attribute was deleted after the value was last updated */
- {
- if (!value_distinguished_at_csn(e, a, current_value, current_value_vucsn)) {
- entry_present_value_to_zapped_value(a, current_value);
- current_value = NULL;
- current_value_vucsn = NULL;
- }
- }
+
+ } else {
+ /* Here the current_value is older than the second_current_value */
+ if (value_distinguished_at_csn(e, a, current_value, (const CSN *)second_current_value_vucsn)) {
+ /* current_value was distinguished at the time the second value was added
+ * then the current_value should become the current */
+ value_to_zap = second_current_value;
+ } else {
+ value_to_zap = current_value;
}
- } else /* addition of a new value */
- {
- const CSN *new_value_vucsn = value_get_csn(new_value, CSN_TYPE_VALUE_UPDATED);
- if (csn_compare(new_value_vucsn, current_value_vucsn) < 0) {
- /*
- * if the new value was distinguished at the time the current value was added
- * then the new value should become current
+ }
+ entry_present_value_to_zapped_value(a, value_to_zap);
+
+
+
+}
+
+/* This routine applies for single valued attribute.
+ * It checks if the deleted value is more recent than
+ * the present one. If it is, it resurect the deleted value
+ *
+ * This function leaves untouch the adcsn
+ */
+static void
+resolve_single_valued_check_restore_deleted_value(Slapi_Entry *e, Slapi_Attr *a)
+{
+ Slapi_Value *deleted_value = NULL;
+ Slapi_Value *current_value = NULL;
+
+ /* Retrieve the deleted and current value */
+ deleted_value = attr_most_recent_deleted_value(a);
+ if (deleted_value == NULL) {
+ return;
+ }
+ slapi_attr_first_value(a, ¤t_value);
+
+ if (current_value == NULL) {
+ /* An attribute needs a present value */
+ entry_deleted_value_to_present_value(a, deleted_value);
+ } else {
+ CSN *current_value_vucsn;
+ CSN *deleted_value_vucsn;
+ CSN *deleted_value_vdcsn;
+
+ deleted_value_vucsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_UPDATED);
+ deleted_value_vdcsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_DELETED);
+ current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
+ if (deleted_value_vucsn &&
+ !value_distinguished_at_csn(e, a, current_value, (const CSN *)deleted_value_vucsn) &&
+ (csn_compare((const CSN *)current_value_vucsn, (const CSN *)deleted_value_vucsn) < 0) &&
+ (csn_compare((const CSN *)deleted_value_vdcsn, (const CSN *)current_value_vucsn) < 0)) {
+ /* the condition to resurrect the deleted value is
+ * - it is more recent than the current value
+ * - its value was deleted before the current value
+ * - the current value is not distinguished
*/
- if (value_distinguished_at_csn(e, a, new_value, current_value_vucsn)) {
- /* attribute.pending_value = attribute.current_value */
- /* attribute.current_value = new_value */
- if (pending_value == NULL) {
- entry_present_value_to_deleted_value(a, current_value);
- } else {
- entry_present_value_to_zapped_value(a, current_value);
- }
- pending_value = current_value;
- current_value = new_value;
- new_value = NULL;
- pending_value_vucsn = current_value_vucsn;
- current_value_vucsn = new_value_vucsn;
- } else {
- /* new_value= NULL */
- entry_present_value_to_zapped_value(a, new_value);
- new_value = NULL;
- }
- } else /* new value is after the current value */
- {
- if (!value_distinguished_at_csn(e, a, current_value, new_value_vucsn)) {
- /* attribute.current_value = new_value */
- entry_present_value_to_zapped_value(a, current_value);
- current_value = new_value;
- new_value = NULL;
- current_value_vucsn = new_value_vucsn;
- } else /* value is distinguished - check if we should replace the current pending value */
- {
- if (csn_compare(new_value_vucsn, pending_value_vucsn) > 0) {
- /* attribute.pending_value = new_value */
- entry_deleted_value_to_zapped_value(a, pending_value);
- entry_present_value_to_deleted_value(a, new_value);
- pending_value = new_value;
- new_value = NULL;
- pending_value_vucsn = new_value_vucsn;
- }
- }
+ entry_present_value_to_zapped_value(a, current_value);
+ entry_deleted_value_to_present_value(a, deleted_value);
}
}
+}
+/* This function deals with single valued attribute
+ * It zap the current value if the adcsn is more recent and the value is not distinguished
+ */
+static void
+resolve_single_valued_zap_current(Slapi_Entry *e, Slapi_Attr *a)
+{
+ Slapi_Value *current_value = NULL;
+ CSN *current_value_vucsn;
+ CSN *adcsn;
- /*
- * This call ensures that the attribute does not have a pending_value
- * or a deletion_csn that is earlier than the current_value.
+ /* check if the current value should be deleted because
+ * older than adcsn and not distinguished
*/
- /* purge_attribute_state_single_valued */
- if ((pending_value != NULL && (csn_compare(adcsn, pending_value_vucsn) < 0)) ||
- (pending_value == NULL && (csn_compare(adcsn, current_value_vucsn) < 0))) {
+ slapi_attr_first_value(a, ¤t_value);
+ current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
+ adcsn = attr_get_deletion_csn(a);
+ if (current_value != NULL) {
+ if (csn_compare((const CSN *)adcsn, (const CSN *) current_value_vucsn) > 0) {
+ /* the attribute was deleted after the value was last updated */
+ if (!value_distinguished_at_csn(e, a, current_value, (const CSN *) current_value_vucsn)) {
+ entry_present_value_to_zapped_value(a, current_value);
+ }
+ }
+ }
+}
+/* This function deals with single valued attribute
+ * It reset the adcsn if
+ * - there is no deleted value and current value is more recent than the adcsn
+ * - there is a deleted value and it is more recent than the adcsn
+ */
+static void
+resolve_single_valued_set_adcsn(Slapi_Attr *a)
+{
+ Slapi_Value *deleted_value = NULL;
+ Slapi_Value *current_value = NULL;
+ CSN *current_value_vucsn;
+ CSN *deleted_value_vucsn;
+ CSN *adcsn;
+
+ slapi_attr_first_value(a, ¤t_value);
+ current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
+ deleted_value = attr_most_recent_deleted_value(a);
+ deleted_value_vucsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_UPDATED);
+ adcsn = attr_get_deletion_csn(a);
+ if ((deleted_value != NULL && (csn_compare(adcsn, (const CSN *) deleted_value_vucsn) < 0)) ||
+ (deleted_value == NULL && (csn_compare(adcsn, (const CSN *) current_value_vucsn) < 0))) {
attr_set_deletion_csn(a, NULL);
- adcsn = NULL;
}
+}
+/* This function deals with single valued attribute
+ * It checks if the deleted value worth to be kept
+ *
+ * deleted value is zapped if
+ * - it is the result of MOD_REPL that is older than current value
+ * - It is the result of MOD_DEL_<value> that is belong to the same operation that set the current value
+ */
+static void
+resolve_single_valued_zap_deleted(Slapi_Attr *a)
+{
+ Slapi_Value *deleted_value = NULL;
+ Slapi_Value *current_value = NULL;
+ CSN *current_value_vucsn;
+ CSN *deleted_value_vucsn;
+ CSN *deleted_value_vdcsn;
+ CSN *deleted_value_csn;
+ PRBool deleted_on_mod_del = PR_FALSE; /* flag if a value was deleted specifically */
+
+ /* Now determine if the deleted value worth to be kept */
+ slapi_attr_first_value(a, ¤t_value);
+ current_value_vucsn = value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
+
+ deleted_value = attr_most_recent_deleted_value(a);
+ deleted_value_vucsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_UPDATED);
+ deleted_value_vdcsn = value_get_csn(deleted_value, CSN_TYPE_VALUE_DELETED);
+
+ /* get the appropriate csn to take into consideration: either from MOD_REPL or from MOD_DEL_specific */
+ if (csn_compare((const CSN *) deleted_value_vdcsn, (const CSN *) deleted_value_vucsn) <= 0) {
+ deleted_value_csn = deleted_value_vucsn;
+ } else {
+ deleted_value_csn = deleted_value_vdcsn;
+ if (0 == csn_compare_ext((const CSN *) current_value_vucsn, (const CSN *) deleted_value_vdcsn, CSN_COMPARE_SKIP_SUBSEQ)) {
+ /* the deleted value was specifically delete in the same operation that set the current value */
+ deleted_on_mod_del = PR_TRUE;
+ }
+ }
+ if ((csn_compare((const CSN *) deleted_value_csn, (const CSN *) current_value_vucsn) < 0) || deleted_on_mod_del) {
+ entry_deleted_value_to_zapped_value(a, deleted_value);
+ }
+}
+
+/* This function deals with single valued attribute
+ * It does a set of cleanup in the current/deleted values in order
+ * to conform the schema, take care of distinguished values and only preserve the
+ * values that worth to be kept.
+ */
+static void
+resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribute_state)
+{
+ int32_t nbval, i;
+ Slapi_Value *current_value = NULL;
+
+ /* retrieve the current value(s) */
+ slapi_attr_get_numvalues(a, &nbval);
+ i = slapi_attr_first_value(a, ¤t_value);
+
+ /* If there are several values, first determine which value will be the current (present) one */
+ if (nbval > 1) {
+ /* There are several values for a single valued attribute, keep the most recent one */
+ if (i == -1) {
+ slapi_log_err(SLAPI_LOG_ERR, "resolve_attribute_state_single_valued", "Unexpected state of %s that contains more than one value but can not read the second\n", a->a_type);
+ } else {
+ Slapi_Value *second_current_value = NULL;
+
+ slapi_attr_next_value(a, i, &second_current_value);
+ resolve_single_valued_two_values(e, a, attribute_state, current_value, second_current_value);
+ }
+ }
+ /* There is only one current value (present value) */
+
+ /* Now determine if the deleted value needs to replace the current value */
+ resolve_single_valued_check_restore_deleted_value(e, a);
+
+ /* Now determine if the deleted value worth to be kept (vs. current value) */
+ resolve_single_valued_zap_deleted(a);
+
+ /* Now determine if the current value worth to be kept (vs. adcsn) */
+ resolve_single_valued_zap_current(e, a);
+
+ /* Now set the adcsn */
+ resolve_single_valued_set_adcsn(a);
- /* set attribute state */
+ /* set the attribute in the correct list in the entry: present or deleted */
+ slapi_attr_first_value(a, ¤t_value);
if (current_value == NULL) {
if (attribute_state == ATTRIBUTE_PRESENT) {
entry_present_attribute_to_deleted_attribute(e, a);
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years, 2 months
[389-ds-base] branch 389-ds-base-1.3.8 updated: Ticket 50177 - import task should not be deleted too rapidely after import finishes to be able to query the status
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
tbordaz pushed a commit to branch 389-ds-base-1.3.8
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.3.8 by this push:
new 26517ea Ticket 50177 - import task should not be deleted too rapidely after import finishes to be able to query the status
26517ea is described below
commit 26517eadf066f34b4fb75527a1a439cbaba258e1
Author: Thierry Bordaz <tbordaz(a)redhat.com>
AuthorDate: Fri Feb 1 15:36:01 2019 +0100
Ticket 50177 - import task should not be deleted too rapidely after import finishes to be able to query the status
Bug Description:
scripts that create online import and export tasks do not define a Time To Life of the tasks.
As a consequence the task entry is cleared 2min (default value) after task completion.
This is too rapid and some admin scripts may miss the final task status.
Fix Description:
The fix is to keep the entry of completed online import and export tasks for 1 day.
It also allows defines a default TTL to 1h (instead of 2min)
https://pagure.io/389-ds-base/issue/50177
Reviewed by: Mark Reynolds
Platforms tested: F27
Flag Day: no
Doc impact: no
---
ldap/admin/src/scripts/db2ldif.pl.in | 3 ++-
ldap/admin/src/scripts/ldif2db.pl.in | 3 ++-
ldap/servers/slapd/task.c | 6 +++---
3 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/ldap/admin/src/scripts/db2ldif.pl.in b/ldap/admin/src/scripts/db2ldif.pl.in
index 0d220f0..f7d12b4 100644
--- a/ldap/admin/src/scripts/db2ldif.pl.in
+++ b/ldap/admin/src/scripts/db2ldif.pl.in
@@ -241,7 +241,8 @@ if ($decrypt_on_export != 0) { $nsexportdecrypt = "nsExportDecrypt: true\n"; }
$nsprintkey = "";
if ($printkey == 0) { $nsprintkey = "nsPrintKey: false\n"; }
$nsldiffile = "nsFilename: ${ldiffile}\n";
-$entry = "${dn}${misc}${cn}${nsinstance}${nsincluded}${nsexcluded}${nsreplica}${nsnobase64}${nsnowrap}${nsnoversion}${nsnouniqueid}${nsuseid2entry}${nsonefile}${nsexportdecrypt}${nsprintkey}${nsldiffile}";
+$ttl = "ttl: 86400";
+$entry = "${dn}${misc}${cn}${nsinstance}${nsincluded}${nsexcluded}${nsreplica}${nsnobase64}${nsnowrap}${nsnoversion}${nsnouniqueid}${nsuseid2entry}${nsonefile}${nsexportdecrypt}${nsprintkey}${nsldiffile}${ttl}";
print("Exporting to ldif file: ${ldiffile}\n");
$rc = DSUtil::ldapmod($entry, %info);
diff --git a/ldap/admin/src/scripts/ldif2db.pl.in b/ldap/admin/src/scripts/ldif2db.pl.in
index a5d834f..486dcd0 100644
--- a/ldap/admin/src/scripts/ldif2db.pl.in
+++ b/ldap/admin/src/scripts/ldif2db.pl.in
@@ -192,7 +192,8 @@ $nsmergechunksiz = "nsImportChunkSize: ${mergechunksiz}\n";
$nsgenuniqid = "nsUniqueIdGenerator: ${genuniqid}\n";
$nsuniqidname = "";
if ($uniqidname ne "") { $nsuniqidname = "nsUniqueIdGeneratorNamespace: ${uniqidname}\n"; }
-$entry = "${dn}${misc}${cn}${nsinstance}${nsincluded}${nsexcluded}${nsldiffiles}${nsnoattrindexes}${nsimportencrypt}${nsmergechunksiz}${nsgenuniqid}${nsuniqidname}";
+$ttl = "ttl: 86400";
+$entry = "${dn}${misc}${cn}${nsinstance}${nsincluded}${nsexcluded}${nsldiffiles}${nsnoattrindexes}${nsimportencrypt}${nsmergechunksiz}${nsgenuniqid}${nsuniqidname}${ttl}";
$rc = DSUtil::ldapmod($entry, %info);
diff --git a/ldap/servers/slapd/task.c b/ldap/servers/slapd/task.c
index 0cf0cd7..80a2383 100644
--- a/ldap/servers/slapd/task.c
+++ b/ldap/servers/slapd/task.c
@@ -46,7 +46,7 @@ static int shutting_down = 0;
#define TASK_PROGRESS_NAME "nsTaskCurrentItem"
#define TASK_WORK_NAME "nsTaskTotalItems"
-#define DEFAULT_TTL "120" /* seconds */
+#define DEFAULT_TTL "3600" /* seconds */
#define TASK_SYSCONFIG_FILE_ATTR "sysconfigfile" /* sysconfig reload task file attr */
#define TASK_SYSCONFIG_LOGCHANGES_ATTR "logchanges"
#define TASK_TOMBSTONE_FIXUP "fixup tombstones task"
@@ -387,8 +387,8 @@ slapi_task_status_changed(Slapi_Task *task)
if (e == NULL)
return;
ttl = atoi(slapi_fetch_attr(e, "ttl", DEFAULT_TTL));
- if (ttl > 3600)
- ttl = 3600; /* be reasonable. */
+ if (ttl > (24*3600))
+ ttl = (24*3600); /* be reasonable, allow to check task status not longer than one day */
expire = time(NULL) + ttl;
task->task_flags |= SLAPI_TASK_DESTROYING;
/* queue an event to destroy the state info */
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years, 2 months
[389-ds-base] branch 389-ds-base-1.3.9 updated: Ticket 50177 - import task should not be deleted too rapidely after import finishes to be able to query the status
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
tbordaz pushed a commit to branch 389-ds-base-1.3.9
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.3.9 by this push:
new 50240de Ticket 50177 - import task should not be deleted too rapidely after import finishes to be able to query the status
50240de is described below
commit 50240dea4d6772dbfa482d9335769cf0545863aa
Author: Thierry Bordaz <tbordaz(a)redhat.com>
AuthorDate: Fri Feb 1 15:36:01 2019 +0100
Ticket 50177 - import task should not be deleted too rapidely after import finishes to be able to query the status
Bug Description:
scripts that create online import and export tasks do not define a Time To Life of the tasks.
As a consequence the task entry is cleared 2min (default value) after task completion.
This is too rapid and some admin scripts may miss the final task status.
Fix Description:
The fix is to keep the entry of completed online import and export tasks for 1 day.
It also allows defines a default TTL to 1h (instead of 2min)
https://pagure.io/389-ds-base/issue/50177
Reviewed by: Mark Reynolds
Platforms tested: F27
Flag Day: no
Doc impact: no
---
ldap/admin/src/scripts/db2ldif.pl.in | 3 ++-
ldap/admin/src/scripts/ldif2db.pl.in | 3 ++-
ldap/servers/slapd/task.c | 6 +++---
3 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/ldap/admin/src/scripts/db2ldif.pl.in b/ldap/admin/src/scripts/db2ldif.pl.in
index 0d220f0..f7d12b4 100644
--- a/ldap/admin/src/scripts/db2ldif.pl.in
+++ b/ldap/admin/src/scripts/db2ldif.pl.in
@@ -241,7 +241,8 @@ if ($decrypt_on_export != 0) { $nsexportdecrypt = "nsExportDecrypt: true\n"; }
$nsprintkey = "";
if ($printkey == 0) { $nsprintkey = "nsPrintKey: false\n"; }
$nsldiffile = "nsFilename: ${ldiffile}\n";
-$entry = "${dn}${misc}${cn}${nsinstance}${nsincluded}${nsexcluded}${nsreplica}${nsnobase64}${nsnowrap}${nsnoversion}${nsnouniqueid}${nsuseid2entry}${nsonefile}${nsexportdecrypt}${nsprintkey}${nsldiffile}";
+$ttl = "ttl: 86400";
+$entry = "${dn}${misc}${cn}${nsinstance}${nsincluded}${nsexcluded}${nsreplica}${nsnobase64}${nsnowrap}${nsnoversion}${nsnouniqueid}${nsuseid2entry}${nsonefile}${nsexportdecrypt}${nsprintkey}${nsldiffile}${ttl}";
print("Exporting to ldif file: ${ldiffile}\n");
$rc = DSUtil::ldapmod($entry, %info);
diff --git a/ldap/admin/src/scripts/ldif2db.pl.in b/ldap/admin/src/scripts/ldif2db.pl.in
index a5d834f..486dcd0 100644
--- a/ldap/admin/src/scripts/ldif2db.pl.in
+++ b/ldap/admin/src/scripts/ldif2db.pl.in
@@ -192,7 +192,8 @@ $nsmergechunksiz = "nsImportChunkSize: ${mergechunksiz}\n";
$nsgenuniqid = "nsUniqueIdGenerator: ${genuniqid}\n";
$nsuniqidname = "";
if ($uniqidname ne "") { $nsuniqidname = "nsUniqueIdGeneratorNamespace: ${uniqidname}\n"; }
-$entry = "${dn}${misc}${cn}${nsinstance}${nsincluded}${nsexcluded}${nsldiffiles}${nsnoattrindexes}${nsimportencrypt}${nsmergechunksiz}${nsgenuniqid}${nsuniqidname}";
+$ttl = "ttl: 86400";
+$entry = "${dn}${misc}${cn}${nsinstance}${nsincluded}${nsexcluded}${nsldiffiles}${nsnoattrindexes}${nsimportencrypt}${nsmergechunksiz}${nsgenuniqid}${nsuniqidname}${ttl}";
$rc = DSUtil::ldapmod($entry, %info);
diff --git a/ldap/servers/slapd/task.c b/ldap/servers/slapd/task.c
index 0cf0cd7..80a2383 100644
--- a/ldap/servers/slapd/task.c
+++ b/ldap/servers/slapd/task.c
@@ -46,7 +46,7 @@ static int shutting_down = 0;
#define TASK_PROGRESS_NAME "nsTaskCurrentItem"
#define TASK_WORK_NAME "nsTaskTotalItems"
-#define DEFAULT_TTL "120" /* seconds */
+#define DEFAULT_TTL "3600" /* seconds */
#define TASK_SYSCONFIG_FILE_ATTR "sysconfigfile" /* sysconfig reload task file attr */
#define TASK_SYSCONFIG_LOGCHANGES_ATTR "logchanges"
#define TASK_TOMBSTONE_FIXUP "fixup tombstones task"
@@ -387,8 +387,8 @@ slapi_task_status_changed(Slapi_Task *task)
if (e == NULL)
return;
ttl = atoi(slapi_fetch_attr(e, "ttl", DEFAULT_TTL));
- if (ttl > 3600)
- ttl = 3600; /* be reasonable. */
+ if (ttl > (24*3600))
+ ttl = (24*3600); /* be reasonable, allow to check task status not longer than one day */
expire = time(NULL) + ttl;
task->task_flags |= SLAPI_TASK_DESTROYING;
/* queue an event to destroy the state info */
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years, 2 months
[389-ds-base] branch 389-ds-base-1.4.0 updated: Ticket 50177 - import task should not be deleted too rapidely after import finishes to be able to query the status
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
tbordaz pushed a commit to branch 389-ds-base-1.4.0
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.4.0 by this push:
new 98bfccc Ticket 50177 - import task should not be deleted too rapidely after import finishes to be able to query the status
98bfccc is described below
commit 98bfccc8168d021e2c1516c5042d68c12b88c7e6
Author: Thierry Bordaz <tbordaz(a)redhat.com>
AuthorDate: Fri Feb 1 15:36:01 2019 +0100
Ticket 50177 - import task should not be deleted too rapidely after import finishes to be able to query the status
Bug Description:
scripts that create online import and export tasks do not define a Time To Life of the tasks.
As a consequence the task entry is cleared 2min (default value) after task completion.
This is too rapid and some admin scripts may miss the final task status.
Fix Description:
The fix is to keep the entry of completed online import and export tasks for 1 day.
It also allows defines a default TTL to 1h (instead of 2min)
https://pagure.io/389-ds-base/issue/50177
Reviewed by: Mark Reynolds
Platforms tested: F27
Flag Day: no
Doc impact: no
---
ldap/admin/src/scripts/db2ldif.pl.in | 3 ++-
ldap/admin/src/scripts/ldif2db.pl.in | 3 ++-
ldap/servers/slapd/task.c | 6 +++---
3 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/ldap/admin/src/scripts/db2ldif.pl.in b/ldap/admin/src/scripts/db2ldif.pl.in
index 0d220f0..f7d12b4 100644
--- a/ldap/admin/src/scripts/db2ldif.pl.in
+++ b/ldap/admin/src/scripts/db2ldif.pl.in
@@ -241,7 +241,8 @@ if ($decrypt_on_export != 0) { $nsexportdecrypt = "nsExportDecrypt: true\n"; }
$nsprintkey = "";
if ($printkey == 0) { $nsprintkey = "nsPrintKey: false\n"; }
$nsldiffile = "nsFilename: ${ldiffile}\n";
-$entry = "${dn}${misc}${cn}${nsinstance}${nsincluded}${nsexcluded}${nsreplica}${nsnobase64}${nsnowrap}${nsnoversion}${nsnouniqueid}${nsuseid2entry}${nsonefile}${nsexportdecrypt}${nsprintkey}${nsldiffile}";
+$ttl = "ttl: 86400";
+$entry = "${dn}${misc}${cn}${nsinstance}${nsincluded}${nsexcluded}${nsreplica}${nsnobase64}${nsnowrap}${nsnoversion}${nsnouniqueid}${nsuseid2entry}${nsonefile}${nsexportdecrypt}${nsprintkey}${nsldiffile}${ttl}";
print("Exporting to ldif file: ${ldiffile}\n");
$rc = DSUtil::ldapmod($entry, %info);
diff --git a/ldap/admin/src/scripts/ldif2db.pl.in b/ldap/admin/src/scripts/ldif2db.pl.in
index a5d834f..486dcd0 100644
--- a/ldap/admin/src/scripts/ldif2db.pl.in
+++ b/ldap/admin/src/scripts/ldif2db.pl.in
@@ -192,7 +192,8 @@ $nsmergechunksiz = "nsImportChunkSize: ${mergechunksiz}\n";
$nsgenuniqid = "nsUniqueIdGenerator: ${genuniqid}\n";
$nsuniqidname = "";
if ($uniqidname ne "") { $nsuniqidname = "nsUniqueIdGeneratorNamespace: ${uniqidname}\n"; }
-$entry = "${dn}${misc}${cn}${nsinstance}${nsincluded}${nsexcluded}${nsldiffiles}${nsnoattrindexes}${nsimportencrypt}${nsmergechunksiz}${nsgenuniqid}${nsuniqidname}";
+$ttl = "ttl: 86400";
+$entry = "${dn}${misc}${cn}${nsinstance}${nsincluded}${nsexcluded}${nsldiffiles}${nsnoattrindexes}${nsimportencrypt}${nsmergechunksiz}${nsgenuniqid}${nsuniqidname}${ttl}";
$rc = DSUtil::ldapmod($entry, %info);
diff --git a/ldap/servers/slapd/task.c b/ldap/servers/slapd/task.c
index b145176..8741570 100644
--- a/ldap/servers/slapd/task.c
+++ b/ldap/servers/slapd/task.c
@@ -46,7 +46,7 @@ static int shutting_down = 0;
#define TASK_PROGRESS_NAME "nsTaskCurrentItem"
#define TASK_WORK_NAME "nsTaskTotalItems"
-#define DEFAULT_TTL "120" /* seconds */
+#define DEFAULT_TTL "3600" /* seconds */
#define TASK_SYSCONFIG_FILE_ATTR "sysconfigfile" /* sysconfig reload task file attr */
#define TASK_SYSCONFIG_LOGCHANGES_ATTR "logchanges"
#define TASK_TOMBSTONE_FIXUP "fixup tombstones task"
@@ -381,8 +381,8 @@ slapi_task_status_changed(Slapi_Task *task)
if (e == NULL)
return;
ttl = atoi(slapi_fetch_attr(e, "ttl", DEFAULT_TTL));
- if (ttl > 3600)
- ttl = 3600; /* be reasonable. */
+ if (ttl > (24*3600))
+ ttl = (24*3600); /* be reasonable, allow to check task status not longer than one day */
expire = time(NULL) + ttl;
task->task_flags |= SLAPI_TASK_DESTROYING;
/* queue an event to destroy the state info */
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years, 2 months