blob: f26eb736fd0f8e5b8be7eafa5887bfea17c7d7b0 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.directory.server.core.changelog;
import static org.apache.directory.server.core.integ.IntegrationUtils.getAdminConnection;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import org.apache.directory.ldap.client.api.LdapConnection;
import org.apache.directory.server.core.annotations.CreateDS;
import org.apache.directory.server.core.factory.DefaultDirectoryServiceFactory;
import org.apache.directory.server.core.integ.AbstractLdapTestUnit;
import org.apache.directory.server.core.integ.FrameworkRunner;
import org.apache.directory.server.core.integ.IntegrationUtils;
import org.apache.directory.shared.ldap.constants.SchemaConstants;
import org.apache.directory.shared.ldap.entry.DefaultEntry;
import org.apache.directory.shared.ldap.entry.Entry;
import org.apache.directory.shared.ldap.entry.EntryAttribute;
import org.apache.directory.shared.ldap.exception.LdapException;
import org.apache.directory.shared.ldap.message.ModifyRequest;
import org.apache.directory.shared.ldap.codec.message.ModifyRequestImpl;
import org.apache.directory.shared.ldap.name.DN;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Used to test the default change log implementation with an in memory
* change log store. Note that this will probably be removed since this
* functionality will be used and tested anyway in all other test cases.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
@RunWith(FrameworkRunner.class)
@CreateDS(factory = DefaultDirectoryServiceFactory.class, name = "DefaultChangeLogIT-class")
public class DefaultChangeLogIT extends AbstractLdapTestUnit
{
public static final Logger LOG = LoggerFactory.getLogger( DefaultChangeLogIT.class );
@After
public void closeConnections()
{
IntegrationUtils.closeConnections();
}
@Test
public void testManyTagsPersistenceAcrossRestarts() throws Exception, InterruptedException
{
LdapConnection sysRoot = getAdminConnection( service );
long revision = service.getChangeLog().getCurrentRevision();
// add new test entry
Entry entry = new DefaultEntry( new DN( "ou=test0,ou=system" ) );
entry.add( SchemaConstants.OBJECT_CLASS_AT, "organizationalUnit" );
entry.add( SchemaConstants.OU_AT, "test0" );
sysRoot.add( entry );
assertEquals( revision + 1, service.getChangeLog().getCurrentRevision() );
Tag t0 = service.getChangeLog().tag();
assertEquals( t0, service.getChangeLog().getLatest() );
assertEquals( revision + 1, service.getChangeLog().getCurrentRevision() );
assertEquals( revision + 1, t0.getRevision() );
// add another test entry
entry = new DefaultEntry( new DN( "ou=test1,ou=system" ) );
entry.add( SchemaConstants.OBJECT_CLASS_AT, "organizationalUnit" );
entry.put( SchemaConstants.OU_AT, "test1" );
sysRoot.add( entry );
assertEquals( revision + 2, service.getChangeLog().getCurrentRevision() );
Tag t1 = service.getChangeLog().tag();
assertEquals( t1, service.getChangeLog().getLatest() );
assertEquals( revision + 2, service.getChangeLog().getCurrentRevision() );
assertEquals( revision + 2, t1.getRevision() );
service.shutdown();
service.startup();
sysRoot = getAdminConnection( service );
assertEquals( revision + 2, service.getChangeLog().getCurrentRevision() );
assertEquals( t1, service.getChangeLog().getLatest() );
assertEquals( revision + 2, t1.getRevision() );
// add third test entry
entry = new DefaultEntry( new DN( "ou=test2,ou=system" ) );
entry.add( SchemaConstants.OBJECT_CLASS_AT, "organizationalUnit" );
entry.put( SchemaConstants.OU_AT, "test2" );
sysRoot.add( entry );
assertEquals( revision + 3, service.getChangeLog().getCurrentRevision() );
service.revert();
assertPresent( sysRoot, "ou=test0,ou=system" ); // test present
assertPresent( sysRoot, "ou=test1,ou=system" ); // test present
assertNotPresent( sysRoot, "ou=test2,ou=system" );
assertEquals( revision + 4, service.getChangeLog().getCurrentRevision() );
assertEquals( t1, service.getChangeLog().getLatest() );
service.revert( t0.getRevision() );
assertPresent( sysRoot, "ou=test0,ou=system" ); // test present
assertNotPresent( sysRoot, "ou=test1,ou=system" );
assertNotPresent( sysRoot, "ou=test2,ou=system" );
assertEquals( revision + 7, service.getChangeLog().getCurrentRevision() );
assertEquals( t1, service.getChangeLog().getLatest() );
// no sync this time but should happen automatically
service.shutdown();
service.startup();
sysRoot = getAdminConnection( service );
assertEquals( revision + 7, service.getChangeLog().getCurrentRevision() );
assertEquals( t1, service.getChangeLog().getLatest() );
assertEquals( revision + 2, t1.getRevision() );
service.revert( revision );
assertNotPresent( sysRoot, "ou=test0,ou=system" );
assertNotPresent( sysRoot, "ou=test1,ou=system" );
assertNotPresent( sysRoot, "ou=test2,ou=system" );
assertEquals( revision + 14, service.getChangeLog().getCurrentRevision() );
assertEquals( t1, service.getChangeLog().getLatest() );
}
@Test
public void testTagPersistenceAcrossRestarts() throws Exception, InterruptedException
{
LdapConnection sysRoot = getAdminConnection( service );
long revision = service.getChangeLog().getCurrentRevision();
Tag t0 = service.getChangeLog().tag();
assertEquals( t0, service.getChangeLog().getLatest() );
assertEquals( revision, service.getChangeLog().getCurrentRevision() );
// add new test entry
Entry entry = new DefaultEntry( new DN( "ou=test,ou=system" ) );
entry.add( SchemaConstants.OBJECT_CLASS_AT, "organizationalUnit" );
entry.put( SchemaConstants.OU_AT, "test" );
sysRoot.add( entry );
assertEquals( revision + 1, service.getChangeLog().getCurrentRevision() );
service.shutdown();
service.startup();
sysRoot = getAdminConnection( service );
assertEquals( revision + 1, service.getChangeLog().getCurrentRevision() );
assertEquals( t0, service.getChangeLog().getLatest() );
service.revert();
assertNotPresent( sysRoot, "ou=test" );
assertEquals( revision + 2, service.getChangeLog().getCurrentRevision() );
assertEquals( t0, service.getChangeLog().getLatest() );
}
@Test
public void testRevertAddOperations() throws Exception
{
LdapConnection sysRoot = getAdminConnection( service );
Tag t0 = service.getChangeLog().tag();
Entry entry = new DefaultEntry( new DN( "ou=test,ou=system" ) );
entry.add( SchemaConstants.OBJECT_CLASS_AT, "organizationalUnit" );
entry.put( SchemaConstants.OU_AT, "test" );
sysRoot.add( entry );
assertPresent( sysRoot, "ou=test,ou=system" );
service.revert( t0.getRevision() );
assertNotPresent( sysRoot, "ou=test,ou=system" );
}
@Test
public void testRevertAddAndDeleteOperations() throws Exception
{
LdapConnection sysRoot = getAdminConnection( service );
Tag t0 = service.getChangeLog().tag();
// add new test entry
Entry entry = new DefaultEntry( new DN( "ou=test,ou=system" ) );
entry.add( SchemaConstants.OBJECT_CLASS_AT, "organizationalUnit" );
entry.put( SchemaConstants.OU_AT, "test" );
sysRoot.add( entry );
// assert presence
assertPresent( sysRoot, "ou=test,ou=system" );
// delete the test entry and test that it is gone
sysRoot.delete( "ou=test,ou=system" );
assertNotPresent( sysRoot, "ou=test,ou=system" );
// now revert back to begining the added entry is still gone
service.revert( t0.getRevision() );
assertNotPresent( sysRoot, "ou=test" );
}
@Test
public void testRevertDeleteOperations() throws Exception
{
LdapConnection sysRoot = getAdminConnection( service );
Entry entry = new DefaultEntry( new DN( "ou=test,ou=system" ) );
entry.add( SchemaConstants.OBJECT_CLASS_AT, "organizationalUnit" );
entry.put( SchemaConstants.OU_AT, "test" );
sysRoot.add( entry );
// tag after the addition before deletion
Tag t0 = service.getChangeLog().tag();
assertPresent( sysRoot, "ou=test,ou=system" );
// delete the test entry and test that it is gone
sysRoot.delete( "ou=test,ou=system" );
assertNotPresent( sysRoot, "ou=test,ou=system" );
// now revert and assert that the added entry re-appears
service.revert( t0.getRevision() );
assertPresent( sysRoot, "ou=test,ou=system" );
}
@Test
public void testRevertRenameOperations() throws Exception
{
LdapConnection sysRoot = getAdminConnection( service );
Entry entry = new DefaultEntry( new DN( "ou=oldname,ou=system" ) );
entry.add( SchemaConstants.OBJECT_CLASS_AT, "organizationalUnit" );
entry.put( SchemaConstants.OU_AT, "oldname" );
sysRoot.add( entry );
// tag after the addition before rename
Tag t0 = service.getChangeLog().tag();
assertPresent( sysRoot, "ou=oldname,ou=system" );
// rename the test entry and test that the rename occurred
sysRoot.rename( "ou=oldname,ou=system", "ou=newname" );
assertNotPresent( sysRoot, "ou=oldname,ou=system" );
assertPresent( sysRoot, "ou=newname,ou=system" );
// now revert and assert that the rename was reversed
service.revert( t0.getRevision() );
assertPresent( sysRoot, "ou=oldname,ou=system" );
assertNotPresent( sysRoot, "ou=newname,ou=system" );
}
@Test
public void testRevertModifyOperations() throws Exception
{
LdapConnection sysRoot = getAdminConnection( service );
Entry entry = new DefaultEntry( new DN( "ou=test5,ou=system" ) );
entry.add( SchemaConstants.OBJECT_CLASS_AT, "organizationalUnit" );
entry.put( SchemaConstants.OU_AT, "test5" );
sysRoot.add( entry );
// -------------------------------------------------------------------
// Modify ADD Test
// -------------------------------------------------------------------
// tag after the addition before modify ADD
Tag t0 = service.getChangeLog().tag();
assertPresent( sysRoot, "ou=test5,ou=system" );
// modify the test entry to add description and test new attr appears
ModifyRequest modReq = new org.apache.directory.shared.ldap.codec.message.ModifyRequestImpl();
modReq.setName( entry.getDn() );
modReq.add( "description", "a desc value" );
sysRoot.modify( modReq );
Entry resusitated = sysRoot.lookup( "ou=test5,ou=system" );
assertNotNull( resusitated );
EntryAttribute description = resusitated.get( "description" );
assertNotNull( description );
assertEquals( "a desc value", description.getString() );
// now revert and assert that the added entry re-appears
service.revert( t0.getRevision() );
resusitated = sysRoot.lookup( "ou=test5,ou=system" );
assertNotNull( resusitated );
assertNull( resusitated.get( "description" ) );
// -------------------------------------------------------------------
// Modify REPLACE Test
// -------------------------------------------------------------------
// add the attribute again and make sure it is old value
modReq = new org.apache.directory.shared.ldap.codec.message.ModifyRequestImpl();
modReq.setName( resusitated.getDn() );
modReq.add( "description", "old value" );
sysRoot.modify( modReq );
resusitated = sysRoot.lookup( "ou=test5,ou=system" );
assertNotNull( resusitated );
description = resusitated.get( "description" );
assertNotNull( description );
assertEquals( description.getString(), "old value" );
// now tag then replace the value to "new value" and confirm
Tag t1 = service.getChangeLog().tag();
modReq = new org.apache.directory.shared.ldap.codec.message.ModifyRequestImpl();
modReq.setName( resusitated.getDn() );
modReq.replace( "description", "new value" );
sysRoot.modify( modReq );
resusitated = sysRoot.lookup( "ou=test5,ou=system" );
assertNotNull( resusitated );
description = resusitated.get( "description" );
assertNotNull( description );
assertEquals( description.getString(), "new value" );
// now revert and assert the old value is now reverted
service.revert( t1.getRevision() );
resusitated = sysRoot.lookup( "ou=test5,ou=system" );
assertNotNull( resusitated );
description = resusitated.get( "description" );
assertNotNull( description );
assertEquals( description.getString(), "old value" );
// -------------------------------------------------------------------
// Modify REMOVE Test
// -------------------------------------------------------------------
Tag t2 = service.getChangeLog().tag();
modReq = new ModifyRequestImpl();
modReq.setName( resusitated.getDn() );
modReq.remove( "description", "old value" );
sysRoot.modify( modReq );
resusitated = sysRoot.lookup( "ou=test5,ou=system" );
assertNotNull( resusitated );
description = resusitated.get( "description" );
assertNull( description );
// now revert and assert the old value is now reverted
service.revert( t2.getRevision() );
resusitated = sysRoot.lookup( "ou=test5,ou=system" );
assertNotNull( resusitated );
description = resusitated.get( "description" );
assertNotNull( description );
assertEquals( description.getString(), "old value" );
// -------------------------------------------------------------------
// Modify Multi Operation Test
// -------------------------------------------------------------------
// add a userPassword attribute so we can test replacing it
modReq = new org.apache.directory.shared.ldap.codec.message.ModifyRequestImpl();
modReq.setName( resusitated.getDn() );
modReq.add( "userPassword", "to be replaced" );
sysRoot.modify( modReq );
resusitated = sysRoot.lookup( "ou=test5,ou=system" );
assertPassword( resusitated, "to be replaced" );
modReq = new org.apache.directory.shared.ldap.codec.message.ModifyRequestImpl();
modReq.setName( resusitated.getDn() );
modReq.remove( "description", "old value" );
modReq.add( "seeAlso", "ou=added" );
modReq.replace( "userPassword", "a replaced value" );
Tag t3 = service.getChangeLog().tag();
// now make the modification and check that description is gone,
// seeAlso is added, and that the userPassword has been replaced
sysRoot.modify( modReq );
resusitated = sysRoot.lookup( "ou=test5,ou=system" );
assertNotNull( resusitated );
description = resusitated.get( "description" );
assertNull( description );
assertPassword( resusitated, "a replaced value" );
EntryAttribute seeAlso = resusitated.get( "seeAlso" );
assertNotNull( seeAlso );
assertEquals( seeAlso.getString(), "ou=added" );
// now we revert and make sure the old values are as they were
service.revert( t3.getRevision() );
resusitated = sysRoot.lookup( "ou=test5,ou=system" );
assertNotNull( resusitated );
description = resusitated.get( "description" );
assertNotNull( description );
assertEquals( description.getString(), "old value" );
assertPassword( resusitated, "to be replaced" );
seeAlso = resusitated.get( "seeAlso" );
assertNull( seeAlso );
}
private void assertPassword( Entry entry, String password ) throws Exception
{
EntryAttribute userPassword = entry.get( "userPassword" );
assertNotNull( userPassword );
assertTrue( Arrays.equals( password.getBytes(), userPassword.getBytes() ) );
}
private void assertNotPresent( LdapConnection connection, String dn ) throws LdapException
{
Entry se = connection.lookup( dn );
assertNull( se );
}
private void assertPresent( LdapConnection connection, String dn ) throws LdapException
{
Entry entry = connection.lookup( dn );
assertNotNull( entry );
}
}