blob: db14704f58b70c35d45f07169f4da3344eb6f44a [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.mitosis.service;
import java.util.HashMap;
import java.util.Map;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;
import javax.naming.ldap.LdapContext;
import junit.framework.Assert;
import org.apache.directory.shared.ldap.exception.LdapNameNotFoundException;
import org.apache.directory.shared.ldap.message.AttributeImpl;
import org.apache.directory.shared.ldap.message.AttributesImpl;
import org.apache.directory.shared.ldap.message.ModificationItemImpl;
import org.apache.directory.shared.ldap.name.LdapDN;
import org.apache.directory.shared.ldap.schema.DeepTrimToLowerNormalizer;
import org.apache.directory.shared.ldap.schema.OidNormalizer;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
/**
* A test case for {@link ReplicationServiceITest}
*
* @author The Apache Directory Project Team (dev@directory.apache.org)
* @version $Rev$, $Date$
*/
public class ReplicationServiceITest extends AbstractReplicationServiceTestCase
{
private Map<String, OidNormalizer> oids;
@Before public void setUp() throws Exception
{
createReplicas( new String[] { "A", "B", "C" } );
// Initialize OIDs maps for normalization
oids = new HashMap<String, OidNormalizer>();
oids.put( "ou", new OidNormalizer( "ou", new DeepTrimToLowerNormalizer() ) );
oids.put( "organizationalUnitName", new OidNormalizer( "ou", new DeepTrimToLowerNormalizer() ) );
oids.put( "2.5.4.11", new OidNormalizer( "ou", new DeepTrimToLowerNormalizer() ) );
oids.put( "cn", new OidNormalizer( "cn", new DeepTrimToLowerNormalizer() ) );
oids.put( "commonName", new OidNormalizer( "cn", new DeepTrimToLowerNormalizer() ) );
oids.put( "2.5.4.3", new OidNormalizer( "cn", new DeepTrimToLowerNormalizer() ) );
}
@Ignore
@Test public void testOneWay() throws Exception
{
String dn1 = "cn=test,ou=system";
String dn2 = "cn=test2,ou=system";
testOneWayBind( dn1 );
testOneWayModify( dn1 );
testOneWayRename( dn1, dn2, true );
testOneWayRename( dn2, dn1, false );
testOneWayUnbind( dn1 );
}
/**
* Test that the entry created last will win in the case of a conflict.
*
* NOTE: This test is DISABLED as there is an occasional problem when a message is acknowledged
* too quickly, meaning no further messages can be sent until it has timed out (DIRSERVER-998).
*
* @throws Exception on failure
*/
public void disabled_testTwoWayBind() throws Exception
{
LdapContext ctxA = getReplicaContext( "A" );
LdapContext ctxB = getReplicaContext( "B" );
LdapContext ctxC = getReplicaContext( "C" );
Attributes entryA = new AttributesImpl( true );
entryA.put( "cn", "test" );
entryA.put( "sn", "test" );
entryA.put( "ou", "A" );
Attribute oc = new AttributeImpl( "objectClass" );
oc.add( "top" );
oc.add( "person" );
oc.add( "organizationalPerson" );
entryA.put( oc );
ctxA.bind( "cn=test,ou=system", null, entryA );
// Ensure the second bind is undebatebly the second.
Thread.sleep( 100 );
Attributes entryB = new AttributesImpl( true );
entryB.put( "cn", "test" );
entryB.put( "sn", "test" );
entryB.put( "ou", "B" );
entryB.put( oc );
ctxB.bind( "cn=test,ou=system", null, entryB );
// Let both replicas replicate. Note that a replica can only receive
// logs from one peer at a time so we must delay between replications.
replicationServices.get( "A" ).replicate();
Thread.sleep( 5000 );
replicationServices.get( "B" ).replicate();
Thread.sleep( 5000 );
Assert.assertEquals( "B", getAttributeValue( ctxA, "cn=test,ou=system", "ou" ) );
Assert.assertEquals( "B", getAttributeValue( ctxB, "cn=test,ou=system", "ou" ) );
Assert.assertEquals( "B", getAttributeValue( ctxC, "cn=test,ou=system", "ou" ) );
}
private void testOneWayBind( String dn ) throws Exception
{
LdapContext ctxA = getReplicaContext( "A" );
LdapContext ctxB = getReplicaContext( "B" );
LdapContext ctxC = getReplicaContext( "C" );
Attributes entry = new AttributesImpl( true );
entry.put( "cn", "test" );
entry.put( "sn", "test" );
Attribute oc = new AttributeImpl( "objectClass" );
oc.add( "top" );
oc.add( "person" );
oc.add( "organizationalPerson" );
entry.put( oc );
ctxA.bind( dn, null, entry );
replicationServices.get( "A" ).replicate();
Thread.sleep( 5000 );
Assert.assertNotNull( ctxA.lookup( dn ) );
Assert.assertNotNull( ctxB.lookup( dn ) );
Assert.assertNotNull( ctxC.lookup( dn ) );
}
private void testOneWayModify( String dn ) throws Exception
{
LdapContext ctxA = getReplicaContext( "A" );
LdapContext ctxB = getReplicaContext( "B" );
LdapContext ctxC = getReplicaContext( "C" );
String newValue = "anything";
ctxA.modifyAttributes( dn, new ModificationItem[] {
new ModificationItemImpl( DirContext.REPLACE_ATTRIBUTE, new AttributeImpl( "ou", newValue ))} );
replicationServices.get( "A" ).replicate();
Thread.sleep( 5000 );
Assert.assertEquals( newValue, getAttributeValue( ctxB, dn, "ou" ) );
Assert.assertEquals( newValue, getAttributeValue( ctxC, dn, "ou" ) );
}
private void testOneWayRename( String dn1, String dn2, boolean deleteRDN ) throws Exception
{
LdapContext ctxA = getReplicaContext( "A" );
LdapContext ctxB = getReplicaContext( "B" );
LdapContext ctxC = getReplicaContext( "C" );
String oldRDNValue = (String) new LdapDN(dn1).getRdn().getUpValue();
ctxA.addToEnvironment( "java.naming.ldap.deleteRDN", Boolean.toString( deleteRDN ) );
ctxA.rename( dn1, dn2 );
replicationServices.get( "A" ).replicate();
Thread.sleep( 5000 );
assertNotExists( ctxA, dn1 );
assertNotExists( ctxB, dn1 );
assertNotExists( ctxC, dn1 );
Assert.assertNotNull( ctxA.lookup( dn2 ) );
Assert.assertNotNull( ctxB.lookup( dn2 ) );
Assert.assertNotNull( ctxC.lookup( dn2 ) );
Attribute oldRDNAttributeA = ctxA.getAttributes( dn2 ).get( new LdapDN(dn1).getRdn().getUpType() );
Attribute oldRDNAttributeB = ctxB.getAttributes( dn2 ).get( new LdapDN(dn1).getRdn().getUpType() );
Attribute oldRDNAttributeC = ctxC.getAttributes( dn2 ).get( new LdapDN(dn1).getRdn().getUpType() );
boolean oldRDNExistsA = attributeContainsValue( oldRDNAttributeA, oldRDNValue );
boolean oldRDNExistsB = attributeContainsValue( oldRDNAttributeB, oldRDNValue );
boolean oldRDNExistsC = attributeContainsValue( oldRDNAttributeC, oldRDNValue );
if ( deleteRDN )
{
Assert.assertFalse( oldRDNExistsA );
Assert.assertFalse( oldRDNExistsB );
Assert.assertFalse( oldRDNExistsC );
}
else
{
Assert.assertTrue( oldRDNExistsA );
Assert.assertTrue( oldRDNExistsB );
Assert.assertTrue( oldRDNExistsC );
}
}
private void testOneWayUnbind( String dn ) throws Exception
{
LdapContext ctxA = getReplicaContext( "A" );
LdapContext ctxB = getReplicaContext( "B" );
LdapContext ctxC = getReplicaContext( "C" );
ctxA.unbind( dn );
replicationServices.get( "A" ).replicate();
Thread.sleep( 5000 );
assertNotExists( ctxA, dn );
assertNotExists( ctxB, dn );
assertNotExists( ctxC, dn );
}
private void assertNotExists( LdapContext ctx, String dn ) throws NamingException
{
try
{
ctx.lookup( dn );
}
catch ( LdapNameNotFoundException e )
{
// This is expected so return immediately.
return;
}
throw new AssertionError( "The entry exists" );
}
private String getAttributeValue( LdapContext ctx, String name, String attrName ) throws Exception
{
Attribute attr = ctx.getAttributes( name ).get( attrName );
return ( String ) attr.get();
}
private boolean attributeContainsValue( Attribute attribute, Object value ) throws NamingException
{
boolean foundValue = false;
for ( NamingEnumeration ne = attribute.getAll(); ne.hasMore(); )
{
if ( value.equals( ne.next() ) )
{
foundValue = true;
}
}
return foundValue;
}
}