FractionalReplicationTest.java revision e371bf13d3f899f1de594880fafe67b990d65899
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at
* trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
* add the following below this CDDL HEADER, with the fields enclosed
* by brackets "[]" replaced with your own identifying information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2009-2010 Sun Microsystems, Inc.
* Portions Copyright 2011-2013 ForgeRock AS
*/
/**
* Various tests around fractional replication
*/
@SuppressWarnings("javadoc")
public class FractionalReplicationTest extends ReplicationTestCase {
/** The RS */
/** RS port */
private int replServerPort = -1;
/** Represents the real domain to test (replays and filters) */
/** The domain used to send updates to the real domain */
/** Ids of servers */
/** Fractional mode */
private static final int EXCLUDE_FRAC_MODE = 0;
private static final int INCLUDE_FRAC_MODE = 1;
int initWindow = 100;
/** The tracer object for the debug logger */
/** Number of seconds before generating an error if some conditions not met */
private static final int TIMEOUT = 10000;
/** Uuid of the manipulated entry */
private static final String ENTRY_UUID =
"11111111-1111-1111-1111-111111111111";
private static final String ENTRY_UUID2 =
"22222222-2222-2222-2222-222222222222";
private static final String ENTRY_UUID3 =
"33333333-3333-3333-3333-333333333333";
/** Dn of the manipulated entry */
/**
* Optional attribute not part of concerned attributes of the fractional
* configuration during tests. It should not be impacted by fractional
* mechanism
*/
/**
* Optional attribute used as synchronization attribute to know when the
* modify operation has been processed (used as add new attribute in the
* modify operation) It may or may not be part of the filtered attributes,
* depending on the fractional test mode : exclusive or inclusive
*/
/** Second test backend */
if (debugEnabled())
{
}
}
/**
* Before starting the tests configure some stuff
*/
{
super.setUp();
}
/**
* Returns a bunch of single values for fractional-exclude configuration
* attribute
*/
@SuppressWarnings("unused")
private Object[][] testExcludePrecommitProvider()
{
return new Object[][]
{
};
}
/**
* Returns a bunch of single values for fractional-exclude configuration
* attribute
*/
@SuppressWarnings("unused")
private Object[][] testExcludeNightlyProvider()
{
return new Object[][]
{
};
}
/**
* Calls the testExclude test with a small set of data, for precommit test
* purpose
*/
public void testExcludePrecommit(int testProviderLineId,
{
}
/**
* Calls the testExclude test with a larger set of data, for nightly tests
* purpose
*/
public void testExcludeNightly(int testProviderLineId,
{
}
/**
* Performs Add and Modify operations including attributes that are excluded
* with the passed fractional configuration and checks that these attributes
* are not part of the concerned entry.
* Note: testProviderLineId just here to know what is the provider problematic
* line if the test fail: prevent some display like:
* [testng] parameter[0]: [Ljava.lang.String;@151e824
* but have instead:
* [testng] parameter[0]: 6
* [testng] parameter[1]: [Ljava.lang.String;@151e824
*/
private void testExclude(int testProviderLineId,
{
initTest();
try
{
// create fake domain to send operations
// perform add operation
sendAddMsg(true, fractionalConf);
// check that entry has been created and that it does not contain
// forbidden attributes
// perform modify operation (modify forbidden attributes +
// modify authorized attribute (not a no op))
sendModifyMsg(true, fractionalConf);
// Wait for modify operation being replayed and
// check that entry does not contain forbidden attributes
}
finally
{
endTest();
}
}
/**
* Returns a bunch of single values for fractional-include configuration
* attribute
*/
@SuppressWarnings("unused")
private Object[][] testIncludePrecommitProvider()
{
return new Object[][]
{
};
}
/**
* Returns a bunch of single values for fractional-include configuration
* attribute
*/
@SuppressWarnings("unused")
private Object[][] testIncludeNightlyProvider()
{
return new Object[][]
{
};
}
/**
* Calls the testInclude test with a small set of data, for precommit test
* purpose
*/
public void testIncludePrecommit(int testProviderLineId,
{
}
/**
* Calls the testInclude test with a larger set of data, for nightly tests
* purpose
*/
public void testIncludeNightly(int testProviderLineId,
{
}
/**
* Performs Add and Modify operations including attributes that are excluded
* with the passed fractional configuration and checks that these attributes
* are not part of the concerned entry.
* Note: testProviderLineId just here to know what is the provider problematic
* line if the test fail: prevent some display like:
* [testng] parameter[0]: [Ljava.lang.String;@151e824
* but have instead:
* [testng] parameter[0]: 6
* [testng] parameter[1]: [Ljava.lang.String;@151e824
*/
private void testInclude(int testProviderLineId,
{
initTest();
try
{
// create fake domain to send operations
// perform add operation
sendAddMsg(true, fractionalConf);
// check that entry has been created and that it does not contain
// forbidden attributes
// perform modify operation (modify forbidden attributes +
// modify authorized attribute (not a no op))
sendModifyMsg(true, fractionalConf);
}
finally
{
endTest();
}
}
/**
* Creates connects (to the RS) and starts the fake replication domain
* Use the passed generation id.
*/
private void createFakeReplicationDomain(boolean firstBackend,
long generationId) throws Exception
{
// Test connection
// Check connected server port
}
{
TestCaseUtils.initializeTestBackend(false);
}
private void endTest()
{
if (replicationDomain != null)
{
}
if (fractionalDomainCfgEntry != null)
{
}
if (replicationServer != null)
{
}
}
/**
* Creates a fractional domain with the passed configuration.
* Before that, initializes the backend with the root entry and if requested
* with the correct fractional configuration in it
*/
private void createFractionalDomain(boolean initializeDomain,
{
{
boolean addSynchroAttribute = false;
switch (fractionalMode)
{
case EXCLUDE_FRAC_MODE:
fractModeAttrName = "ds-cfg-fractional-exclude";
opFractModeAttrName = "ds-sync-fractional-exclude";
break;
case INCLUDE_FRAC_MODE:
fractModeAttrName = "ds-cfg-fractional-include";
opFractModeAttrName = "ds-sync-fractional-include";
// For inclusive mode, we use an attribute that is added in the modify
// operation to know when the modify operation has been played. The added
// attribute can only be part of the include config to be taken into account
addSynchroAttribute = true;
break;
default:
fail("Unexpected fractional mode.");
}
/**
* Create a root entry with potentially with fractional configuration before domain creation
*/
// Create base entry with correct fractional config
if (initializeDomain)
{
// Add first backend top entry
"objectClass: top\n" +
"objectClass: organization\n" +
// Add fractional config
int i=0;
{
if (i==0)
{
// First string is the class
}
else
{
// Other strings are attributes
}
i++;
}
}
else
{
// Add second backend top entry
"objectClass: top\n" +
"objectClass: domain\n" +
"dc: example\n";
}
/**
* Create the domain with the passed fractional configuration
*/
// Create a config entry ldif, matching passed settings
int i=0;
{
if (i==0)
{
// First string is the class
}
else
{
// Other strings are attributes
}
i++;
}
// Add the config entry to create the replicated domain
"Unable to add the domain config entry: " + configEntryLdif);
}
}
/**
* Creates a new ReplicationServer.
*/
{
}
/**
* This class is the minimum implementation of a Concrete ReplicationDomain
* used to be able to connect to the RS with a known genid. Also to be able
* to send updates
*/
private class FakeReplicationDomain extends ReplicationDomain
{
/**
* A blocking queue that is used to receive updates from the Replication
* Service.
*/
new LinkedBlockingQueue<UpdateMsg>();
/** A string that will be exported should exportBackend be called. */
/**
* A StringBuilder that will be used to build a new String should the import
* be called.
*/
private int exportedEntryCount;
private long generationID = -1;
public FakeReplicationDomain(
int serverID,
int window,
long heartbeatInterval,
long generationId) throws ConfigException
{
}
{
this.exportString = exportString;
this.exportedEntryCount = exportedEntryCount;
}
public long countEntries() throws DirectoryException
{
return exportedEntryCount;
}
{
try
{
} catch (IOException e)
{
}
}
public long getGenerationID()
{
return generationID;
}
{
byte[] buffer = new byte[1000];
int ret;
do
{
try
{
} catch (IOException e)
{
throw new DirectoryException(
}
} while (ret >= 0);
}
{
return true;
}
}
private static final String REPLICATION_GENERATION_ID =
"ds-sync-generation-id";
{
if (resultEntry == null)
{
}
else
{
{
{
}
}
}
return -1;
}
/**
* Send the AddMsg (from the fake replication domain) for the passed entry
* containing the attributes defined in the passed fractional configuration
*/
throws Exception
{
"objectClass: person\n" + "objectClass: organizationalPerson\n";
{
}
"sn: snValue\n" + "cn: cnValue\n" +
// Add attributes concerned by fractional configuration
boolean first = true;
{
if (!first)
{
// First string is the class
}
first = false;
}
// Create an update message to add an entry.
null,
}
/**
* Send (from the fake replication domain) a ModifyMsg for the passed entry
* modifying attributes defined in the passed fractional configuration
*/
throws Exception
{
// Create modifications on the fractional attributes
boolean first = true;
{
if (!first)
{
// First string is the class
}
first = false;
}
// Add modification for the special attribute (modified attribute)
// Add modification for the synchro attribute (added attribute)
attr =
}
/**
* Utility method : Add an entry in the database
*/
{
addOp.setInternalOperation(true);
}
/**
* Check that the just added entry (newEntry) meets the fractional criteria
* filtered
*/
{
{
// Is the added entry of the expected object class ?
{
}
// Go through each interesting attribute and check it is present or not
// according to the fractional mode
boolean first = true;
switch (fractionalMode)
{
case EXCLUDE_FRAC_MODE:
// Exclude mode: attributes should not be there, but OPTIONAL_ATTR
// attribute should
{
if (!first)
{
}
first = false;
}
break;
case INCLUDE_FRAC_MODE:
// Include mode: attributes should be there, but OPTIONAL_ATTR
// attribute should not
{
if (!first)
{
}
first = false;
}
break;
default:
fail("Unexpected fractional mode.");
}
}
}
/**
* Check that the just modified entry (entry) meets the fractional criteria
* filtered
*/
{
{
// Is the added entry of the expected object class ?
{
}
// Go through each interesting attribute and check it has been modifed or
// not according to the fractional mode
boolean first = true;
switch (fractionalMode)
{
case EXCLUDE_FRAC_MODE:
// Exclude mode: attributes should not be there, but OPTIONAL_ATTR
// attribute should have been modified
{
if (!first)
{
}
first = false;
}
break;
case INCLUDE_FRAC_MODE:
// Include mode: attributes should have been modified, but OPTIONAL_ATTR
// attribute should not be there
{
if (!first)
{
}
first = false;
}
break;
default:
fail("Unexpected fractional mode.");
}
// In both modes, SYNCHRO_OPTIONAL_ATTR attribute should have been added
}
}
/**
* Check that the provided entry has a single value attribute which has the
* expected attribute value
*/
{
attributeValue + " but got no attribute");
}
/**
* Returns a bunch of single values for fractional configuration
* attributes
*/
@SuppressWarnings("unused")
private Object[][] testInitWithFullUpdateExcludePrecommitProvider()
{
return new Object[][]
{
};
}
/**
* Returns a bunch of single values for fractional configuration
* attributes
*/
@SuppressWarnings("unused")
private Object[][] testInitWithFullUpdateExcludeNightlyProvider()
{
return new Object[][]
{
};
}
/**
* Calls the testInitWithFullUpdateExclude test with a small set of data, for precommit test
* purpose
*/
public void testInitWithFullUpdateExcludePrecommit(int testProviderLineId,
{
}
/**
* Calls the testInitWithFullUpdateExclude test with a larger set of data, for nightly tests
* purpose
*/
public void testInitWithFullUpdateExcludeNightly(int testProviderLineId,
{
}
/**
* Configures a domain which is not fractional to fractional exclusive,
* then emulates an online full update to initialize the fractional domain and
* have it operational.
* Note: testProviderLineId just here to know what is the provider problematic
* line if the test fail: prevent some display like:
* [testng] parameter[0]: [Ljava.lang.String;@151e824
* but have instead:
* [testng] parameter[0]: 6
* [testng] parameter[1]: [Ljava.lang.String;@151e824
*/
private void testInitWithFullUpdateExclude(int testProviderLineId,
{
initTest();
// We need a backend with a real configuration in cn=config as at import time
// the real domain will check for backend existence in cn=config. So we use
// dc=example,dc=com for this particular test.
// Clear the backend
try
{
/*
* Create replication server and connect fractional domain to it then fake
* domain
*/
// create fractional domain with the passed fractional configuration
// without initializing the backend
// The domain should go in bad gen as backend is not initialized with
// fractional data
// create fake domain to perform the full update
createFakeReplicationDomain(false, generationId);
/*
* Create the LDIF that will be used to initialize the domain from the
* fake one. Initialize the fake domain with it.
*/
// Top Entry
"objectClass: top\n" +
"objectClass: domain\n" +
"dc: example\n" +
{
// Add fractional config
int i=0;
{
if (i==0)
{
// First string is the class
}
else
{
// Other strings are attributes
}
i++;
}
}
// Org Entry
"objectClass: top\n" +
"objectClass: organization\n" +
"o: test2\n\n";
// User entry
"objectClass: person\n" + "objectClass: organizationalPerson\n" +
"objectClass: inetOrgPerson\n" + "sn: snValue\n" + "cn: cnValue\n" +
"uid: 1\n" + "entryUUID: " +
{
// Add attributes concerned by fractional configuration
boolean first = true;
{
if (!first)
{
// First string is the class
}
first = false;
}
}
// Perform full update from fake domain to fractional domain
/*
* Check fractional domain is operational and that filtering has been done
* during the full update
*/
// The domain should go back in normal status
// check that entry has been created and that it does not contain
// forbidden attributes
// perform modify operation (modify forbidden attributes +
// modify authorized attribute (not a no op))
sendModifyMsg(false, fractionalConf);
// Wait for modify operation being replayed and
// check that entry does not contain forbidden attributes
}
finally
{
endTest();
}
}
throws Exception
{
AttributeType synchroAttrType = DirectoryServer.getAttributeType(SYNCHRO_OPTIONAL_ATTR.toLowerCase());
boolean synchroAttrFound = false;
while (timeout > 0)
{
{
synchroAttrFound = true;
break;
}
timeout--;
}
return entry;
}
/**
* Wait for the passed domain to have the desired status or fail if timeout
* waiting.
*/
{
while(nSec > 0)
{
if ( serverStatus == expectedStatus )
{
debugInfo("waitForDomainStatus: expected replication " +
return;
}
nSec--;
}
}
/**
* Returns a bunch of single values for fractional configuration
* attributes
*/
@SuppressWarnings("unused")
private Object[][] testInitWithFullUpdateIncludePrecommitProvider()
{
return new Object[][]
{
};
}
/**
* Returns a bunch of single values for fractional configuration
* attributes
*/
@SuppressWarnings("unused")
private Object[][] testInitWithFullUpdateIncludeNightlyProvider()
{
return new Object[][]
{
};
}
/**
* Calls the testInitWithFullUpdateExclude test with a small set of data, for precommit test
* purpose
*/
public void testInitWithFullUpdateIncludePrecommit(int testProviderLineId,
{
}
/**
* Calls the testInitWithFullUpdateExclude test with a larger set of data, for nightly tests
* purpose
*/
public void testInitWithFullUpdateIncludeNightly(int testProviderLineId,
{
}
/**
* Configures a domain which is not fractional to fractional inclusive,
* then emulates an online full update to initialize the fractional domain and
* have it operational.
* Note: testProviderLineId just here to know what is the provider problematic
* line if the test fail: prevent some display like:
* [testng] parameter[0]: [Ljava.lang.String;@151e824
* but have instead:
* [testng] parameter[0]: 6
* [testng] parameter[1]: [Ljava.lang.String;@151e824
*/
private void testInitWithFullUpdateInclude(int testProviderLineId,
{
initTest();
// We need a backend with a real configuration in cn=config as at import time
// the real domain will check for backend existence in cn=config. So we use
// dc=example,dc=com for this particular test.
// Clear the backend
try
{
/*
* Create replication server and connect fractional domain to it then fake
* domain
*/
// create fractional domain with the passed fractional configuration
// without initializing the backend
// The domain should go in bad gen as backend is not initialized with
// fractional data
// create fake domain to perform the full update
createFakeReplicationDomain(false, generationId);
/*
* Create the LDIF that will be used to initialize the domain from the
* fake one. Initialize the fake domain with it.
*/
// Top Entry
"objectClass: top\n" +
"objectClass: domain\n" +
"dc: example\n" +
{
// Add fractional config
int i=0;
{
if (i==0)
{
// First string is the class
}
else
{
// Other strings are attributes
}
i++;
}
}
// Org Entry
"objectClass: top\n" +
"objectClass: organization\n" +
"o: test2\n\n";
// User entry
"objectClass: person\n" + "objectClass: organizationalPerson\n" +
"objectClass: inetOrgPerson\n" +
"sn: snValue\n" + "cn: cnValue\n" + "uid: 1\n" + "entryUUID: " +
// Add attributes concerned by fractional configuration
boolean first = true;
{
if (!first)
{
// First string is the class
}
first = false;
}
// Perform full update from fake domain to fractional domain
/*
* Chack fractional domain is operational and that filtering has been done
* during the full update
*/
// The domain should go back in normal status
// check that entry has been created and that it does not contain
// forbidden attributes
// perform modify operation (modify forbidden attributes +
// modify authorized attribute (not a no op))
sendModifyMsg(false, fractionalConf);
}
finally
{
endTest();
}
}
/**
* Tests an add operation on an entry with RDN containing forbidden attribute
* by fractional exclude configuration
*/
@Test
public void testAddWithForbiddenAttrInRDNExclude() throws Exception
{
initTest();
try
{
"displayName", "description");
// create fake domain to send operations
// Perform add operation with forbidden attribute in RDN
"objectClass: person\n" + "objectClass: organizationalPerson\n" +
"objectClass: inetOrgPerson\n" + "sn: snValue\n" + "cn: cnValue\n" +
"displayName: ValueToBeKept\ndisplayName: displayNameValue\n";
// Create an update message to add an entry.
null,
/*
* check that entry has been created and has attribute values from RDN
* only
*/
/**
* Now perform same test, but with 2 forbidden attributes in RDN, using '+'
*/
// Perform add operation with forbidden attribute in RDN
entryLdif = "dn: displayName=ValueToBeKept+description=ValueToBeKeptToo," +
"objectClass: person\n" + "objectClass: organizationalPerson\n" +
"sn: snValue\n" + "cn: cnValue\n" +
"displayName: ValueToBeKept\ndisplayName: displayNameValue\n" +
"description: descriptionValue\ndescription: ValueToBeKeptToo\n";
// Create an update message to add an entry.
null,
/*
* check that entry has been created and has attribute values from RDN
* only
*/
}
finally
{
endTest();
}
}
/**
* Tests an add operation on an entry with RDN containing forbidden attribute
* by fractional include configuration
*/
@Test
public void testAddWithForbiddenAttrInRDNInclude() throws Exception
{
initTest();
try
{
"carLicense");
// create fake domain to send operations
// Perform add operation with forbidden attribute in RDN
"objectClass: person\n" + "objectClass: organizationalPerson\n" +
"objectClass: inetOrgPerson\n" + "sn: snValue\n" + "cn: cnValue\n" +
"displayName: ValueToBeKept\ndisplayName: displayNameValue\n" +
"carLicense: cirLicenseValue\n";
// Create an update message to add an entry.
null,
/*
* check that entry has been created and has attribute values from RDN
* only
*/
/**
* Now perform same test, but with 2 forbidden attributes in RDN, using '+'
*/
// Perform add operation with forbidden attribute in RDN
entryLdif = "dn: displayName=ValueToBeKept+description=ValueToBeKeptToo," +
"objectClass: person\n" + "objectClass: organizationalPerson\n" +
"objectClass: inetOrgPerson\n" + "sn: snValue\n" + "cn: cnValue\n" +
"displayName: ValueToBeKept\ndisplayName: displayNameValue\n" +
"description: descriptionValue\ndescription: ValueToBeKeptToo\n" +
"carLicense: cirLicenseValue\n";
// Create an update message to add an entry.
null,
/*
* check that entry has been created and has attribute values from RDN
* only
*/
}
finally
{
endTest();
}
}
/**
* Tests modify dn operation on an entry with old RDN containing forbidden
* attribute by fractional exclude configuration
*/
@Test
public void testModifyDnWithForbiddenAttrInRDNExclude() throws Exception
{
initTest();
try
{
"displayName", "description");
// create fake domain to send operations
// Perform add operation with forbidden attribute in RDN
String entryName = "displayName=ValueToBeKept+description=ValueToBeRemoved," + TEST_ROOT_DN_STRING ;
"objectClass: person\n" + "objectClass: organizationalPerson\n" +
"objectClass: inetOrgPerson\n" + "sn: snValue\n" + "cn: cnValue\n" +
"displayName: ValueToBeKept\ndescription: ValueToBeRemoved\n";
// Create an update message to add an entry.
null,
// check that entry has been created and has attribute values from RDN
/*
* Perform modify dn operation by renaming the entry keeping only one of
* the forbidden attributes
*/
// Create modify dn message to modify the entry.
"displayName=ValueToBeKept", null);
/*
* check that entry has been renamed and has only attribute left in the
* new RDN
*/
}
finally
{
endTest();
}
}
/**
* Tests modify dn operation on an entry with old RDN containing forbidden
* attribute by fractional include configuration
*/
@Test
public void testModifyDnWithForbiddenAttrInRDNInclude() throws Exception
{
initTest();
try
{
"carLicense");
// create fake domain to send operations
// Perform add operation with forbidden attribute in RDN
String entryName = "displayName=ValueToBeKept+description=ValueToBeRemoved," + TEST_ROOT_DN_STRING ;
"objectClass: person\n" + "objectClass: organizationalPerson\n" +
"objectClass: inetOrgPerson\n" + "sn: snValue\n" + "cn: cnValue\n" +
"displayName: ValueToBeKept\ndescription: ValueToBeRemoved\n";
// Create an update message to add an entry.
null,
// check that entry has been created and has attribute values from RDN
/*
* Perform modify dn operation by renaming the entry keeping only one of
* the forbidden attributes
*/
// Create modify dn message to modify the entry.
"displayName=ValueToBeKept", null);
/*
* check that entry has been renamed and has only attribute left in the
* new RDN
*/
}
finally
{
endTest();
}
}
}