def test_segfaults(topo_m2, _delete_after):
    """ns-slapd segfaults while trying to delete a tombstone entry

    :id: 9f8f7388-a64c-11ea-b5f7-8c16451d917b
    :setup: MMR with 2 masters
    :steps:
        1. Add new user
        2. Delete user - should leave tombstone entry
        3. Search for tombstone entry
        4. Try to delete tombstone entry
        5. Check if server is still alive
    :expected results:
        1. Should succeeds
        2. Should succeeds
        3. Should succeeds
        4. Should succeeds
        5. Should succeeds
    """
    m1 = topo_m2.ms["master1"]
    # Add user
    user = UserAccounts(m1, DEFAULT_SUFFIX, rdn=None).create_test_user(uid=10,
                                                                       gid=1)
    # Delete user - should leave tombstone entry
    user.delete()
    tombstones = Tombstones(m1, DEFAULT_SUFFIX)
    # Search for tombstone entry
    fil = tombstones.filter("(&(objectClass=nstombstone)(uid=test_user_10))")
    assert fil
    # Try to delete tombstone entry
    for user in fil:
        user.delete()
    # Check if server is still alive
    assert m1.status()
def test_entryusn_after_repl_delete(topology_m2):
    """Verify that entryUSN is incremented on 1 after delete operation which creates a tombstone

    :id: 1704cf65-41bc-4347-bdaf-20fc2431b218
    :setup: An instance with replication, Users, USN enabled
    :steps:
        1. Try to delete a user
        2. Check the tombstone has the incremented USN
        3. Try to delete ou=People with users
        4. Check the entry has a not incremented entryUSN
    :expectedresults:
        1. Success
        2. Success
        3. Should fail with Not Allowed On Non-leaf error
        4. Success
    """

    inst = topology_m2.ms["supplier1"]
    plugin = USNPlugin(inst)
    plugin.enable()
    inst.restart()
    users = UserAccounts(inst, DEFAULT_SUFFIX)

    try:
        user_1 = users.create_test_user()
        user_rdn = user_1.rdn
        tombstones = Tombstones(inst, DEFAULT_SUFFIX)

        user_1.replace('description', 'update_ts')
        user_usn = user_1.get_attr_val_int('entryusn')

        user_1.delete()
        time.sleep(1)  # Gives a little time for tombstone creation to complete

        ts = tombstones.get(user_rdn)
        ts_usn = ts.get_attr_val_int('entryusn')

        assert (user_usn + 1) == ts_usn

        user_1 = users.create_test_user()
        org = OrganizationalUnit(inst, f"ou=People,{DEFAULT_SUFFIX}")
        org.replace('description', 'update_ts')
        ou_usn_before = org.get_attr_val_int('entryusn')
        try:
            org.delete()
        except ldap.NOT_ALLOWED_ON_NONLEAF:
            pass
        ou_usn_after = org.get_attr_val_int('entryusn')
        assert ou_usn_before == ou_usn_after

    finally:
        try:
            user_1.delete()
        except ldap.NO_SUCH_OBJECT:
            pass
def _create_and_delete_tombstone(topo_m2, id):
    m1 = topo_m2.ms["master1"]
    # Add new user
    user1 = UserAccounts(m1, DEFAULT_SUFFIX, rdn=None).create_test_user(uid=id,
                                                                        gid=id)
    # Delete user - should leave tombstone entry
    user1.delete()
    tombstones = Tombstones(m1, DEFAULT_SUFFIX)
    # Search for tombstone entry
    fil = tombstones.filter(
        "(&(objectClass=nstombstone)(uid=test_user_{}*))".format(id))[0]
    assert fil
    fil.rename("uid=engineer")
    assert m1
def test_purge_success(topology_m1):
    """Verify that tombstones are created successfully

    :id: adb86f50-ae76-4ed6-82b4-3cdc30ccab78
    :setup: Standalone instance
    :steps:
        1. Enable replication to unexisting instance
        2. Add an entry to the replicated suffix
        3. Delete the entry
        4. Check that tombstone entry exists (objectclass=nsTombstone)
    :expectedresults: Tombstone entry exist
        1. Operation should be successful
        2. The entry should be successfully added
        3. The entry should be successfully deleted
        4. Tombstone entry should exist
    """
    m1 = topology_m1.ms['master1']

    users = UserAccounts(m1, DEFAULT_SUFFIX)
    user = users.create(properties=TEST_USER_PROPERTIES)

    tombstones = Tombstones(m1, DEFAULT_SUFFIX)

    assert len(tombstones.list()) == 0

    user.delete()

    assert len(tombstones.list()) == 1
    assert len(users.list()) == 0

    ts = tombstones.get('testuser')
    assert ts.exists()

    if not ds_is_older('1.4.0'):
        ts.revive()

        assert len(users.list()) == 1
        user_revived = users.get('testuser')
def test_precise_tombstone_purging(topology_m1):
    """ Test precise tombstone purging

    :id: adb86f50-ae76-4ed6-82b4-3cdc30ccab79
    :setup: master1 instance
    :steps:
        1. Create and Delete entry to create a tombstone
        2. export ldif, edit, and import ldif
        3. Check tombstones do not contain nsTombstoneCSN
        4. Run fixup task, and verify tombstones now have nsTombstone CSN
        5. Configure tombstone purging
        6. Verify tombstones are purged
    :expectedresults:
        1. Success
        2. Success
        3. Success
        4. Success
        5. Success
        6. Success
    """

    m1 = topology_m1.ms['master1']
    m1_tasks = Tasks(m1)

    # Create tombstone entry
    users = UserAccounts(m1, DEFAULT_SUFFIX)
    user = users.create_test_user(uid=1001)
    user.delete()

    # Verify tombstone was created
    tombstones = Tombstones(m1, DEFAULT_SUFFIX)
    assert len(tombstones.list()) == 1

    # Export db, strip nsTombstoneCSN, and import it
    ldif_file = "{}/export.ldif".format(m1.get_ldif_dir())
    args = {EXPORT_REPL_INFO: True, TASK_WAIT: True}
    m1_tasks.exportLDIF(DEFAULT_SUFFIX, None, ldif_file, args)
    time.sleep(.5)

    # Strip LDIF of nsTombstoneCSN, getthe LDIF lines, the n create new ldif
    ldif = open(ldif_file, "r")
    lines = ldif.readlines()
    ldif.close()
    time.sleep(.5)

    ldif = open(ldif_file, "w")
    for line in lines:
        if not line.lower().startswith('nstombstonecsn'):
            ldif.write(line)
    ldif.close()
    time.sleep(.5)

    # import the new ldif file
    log.info('Import replication LDIF file...')
    args = {TASK_WAIT: True}
    m1_tasks.importLDIF(DEFAULT_SUFFIX, None, ldif_file, args)
    time.sleep(.5)

    # Search for the tombstone again
    tombstones = Tombstones(m1, DEFAULT_SUFFIX)
    assert len(tombstones.list()) == 1

    #
    # Part 3 - test fixup task using the strip option.
    #
    args = {TASK_WAIT: True, TASK_TOMB_STRIP: True}
    m1_tasks.fixupTombstones(DEFAULT_BENAME, args)
    time.sleep(.5)

    # Search for tombstones with nsTombstoneCSN - better not find any
    for ts in tombstones.list():
        assert not ts.present("nsTombstoneCSN")

    # Now run the fixup task
    args = {TASK_WAIT: True}
    m1_tasks.fixupTombstones(DEFAULT_BENAME, args)
    time.sleep(.5)

    # Search for tombstones with nsTombstoneCSN - better find some
    tombstones = Tombstones(m1, DEFAULT_SUFFIX)
    assert len(tombstones.list()) == 1

    #
    # Part 4 - Test tombstone purging
    #
    args = {
        REPLICA_PRECISE_PURGING: b'on',
        REPLICA_PURGE_DELAY: b'5',
        REPLICA_PURGE_INTERVAL: b'5'
    }
    m1.replica.setProperties(DEFAULT_SUFFIX, None, None, args)

    # Wait for the interval to pass
    log.info('Wait for tombstone purge interval to pass...')
    time.sleep(6)

    # Add an entry to trigger replication
    users.create_test_user(uid=1002)

    # Wait for the interval to pass again
    log.info('Wait for tombstone purge interval to pass again...')
    time.sleep(6)

    # search for tombstones, there should be none
    tombstones = Tombstones(m1, DEFAULT_SUFFIX)
    assert len(tombstones.list()) == 0