LocalBackendWorkflowElementTest.java revision 9aa1482c49865483f798f91ef7d16f03cc3ec811
/*
* 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 legal-notices/CDDLv1_0.txt
* or http://forgerock.org/license/CDDLv1.0.html.
* 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 legal-notices/CDDLv1_0.txt.
* 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 2006-2010 Sun Microsystems, Inc.
* Portions Copyright 2011-2015 ForgeRock AS.
*/
package org.opends.server.workflowelement.localbackend;
import java.util.ArrayList;
import org.forgerock.opendj.ldap.ModificationType;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.SearchScope;
import org.opends.server.DirectoryServerTestCase;
import org.opends.server.TestCaseUtils;
import org.opends.server.core.ModifyOperation;
import org.opends.server.core.SearchOperation;
import org.opends.server.protocols.internal.SearchRequest;
import org.opends.server.types.Attribute;
import org.opends.server.types.Attributes;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Modification;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.protocols.internal.InternalClientConnection.*;
import static org.opends.server.protocols.internal.Requests.*;
import static org.testng.Assert.*;
/**
* This set of tests test the LocalBackendWorkflowElement.
*/
@SuppressWarnings("javadoc")
public class LocalBackendWorkflowElementTest extends DirectoryServerTestCase
{
@BeforeClass
public void setUp() throws Exception
{
TestCaseUtils.startServer();
}
/**
* This test checks that workflows are updated as appropriate when backend
* base DNs are added or removed.
* <p>
* When a new backend base DN is added, the new suffix should be accessible
* for the route process - ie. a workflow should be created and be a potential
* candidate for the route process.
* <p>
* Similarly, when a backend base DN is removed its associated workflow should
* be removed; subsequently, any request targeting the removed suffix should
* be rejected and a no such entry status code be returned.
*/
@Test
public void testBackendBaseDNModification() throws Exception
{
String suffix = "dc=example,dc=com";
String suffix2 = "o=workflow suffix";
String backendBaseDNName = "ds-cfg-base-dn";
// Initialize a backend with a base entry.
TestCaseUtils.clearBackend("userRoot", suffix);
// Check that suffix is accessible while suffix2 is not.
searchEntry(suffix, ResultCode.SUCCESS);
searchEntry(suffix2, ResultCode.NO_SUCH_OBJECT);
// Add a new suffix in the backend and create a base entry for the new suffix
String backendConfigDN = "ds-cfg-backend-id=userRoot," + DN_BACKEND_BASE;
modifyAttribute(backendConfigDN, ModificationType.ADD, backendBaseDNName, suffix2);
addBaseEntry(suffix2, "workflow suffix");
// Both old and new suffix should be accessible.
searchEntry(suffix, ResultCode.SUCCESS);
searchEntry(suffix2, ResultCode.SUCCESS);
// Remove the new suffix...
modifyAttribute(backendConfigDN, ModificationType.DELETE, backendBaseDNName, suffix2);
// ...and check that the removed suffix is no more accessible.
searchEntry(suffix, ResultCode.SUCCESS);
searchEntry(suffix2, ResultCode.NO_SUCH_OBJECT);
// Replace the suffix with suffix2 in the backend
modifyAttribute(backendConfigDN, ModificationType.REPLACE, backendBaseDNName, suffix2);
// Now none of the suffixes are accessible: this means the entries
// under the old suffix are not moved to the new suffix.
searchEntry(suffix, ResultCode.NO_SUCH_OBJECT);
searchEntry(suffix2, ResultCode.NO_SUCH_OBJECT);
// Add a base entry for the new suffix
addBaseEntry(suffix2, "workflow suffix");
// The new suffix is accessible while the old one is not.
searchEntry(suffix, ResultCode.NO_SUCH_OBJECT);
searchEntry(suffix2, ResultCode.SUCCESS);
// Reset the configuration with previous suffix
modifyAttribute(backendConfigDN, ModificationType.REPLACE, backendBaseDNName, suffix);
}
/**
* This test checks that the workflow takes into account the subordinate
* naming context defined in the RootDSEBackend.
*/
@Test
public void testNonRootDseSubordinateNamingContext() throws Exception
{
// Backends for the test
String backendID1 = "test-dc-example-dc-com-subordinate1,dc=example,dc=com";
String backendID2 = "test-dc-example-dc-com-subordinate2,dc=example,dc=com";
String backend1 = "o=" + backendID1;
String backend2 = "o=" + backendID2;
try
{
TestCaseUtils.clearDataBackends();
// At this point, the list of subordinate naming context is not defined
// yet (null): any public backend should be visible. Create a backend
// with a base entry and check that the test naming context is visible.
TestCaseUtils.initializeMemoryBackend(backendID1, backend1, true);
searchEntries("dc=example,dc=com", ResultCode.SUCCESS, 1);
// Create another test backend and check that the new backend is visible
TestCaseUtils.initializeMemoryBackend(backendID2, backend2, true);
searchEntries("dc=example,dc=com", ResultCode.SUCCESS, 2);
}
finally
{
// Clean the test backends. There is no more naming context.
TestCaseUtils.clearMemoryBackend(backendID1);
TestCaseUtils.clearMemoryBackend(backendID2);
searchEntries("dc=example,dc=com", ResultCode.NO_SUCH_OBJECT, 0);
}
}
/**
* This test checks that the workflow takes into account the subordinate
* naming context defined in the RootDSEBackend.
*/
@Test
public void testRootDseSubordinateNamingContext() throws Exception
{
// Backends for the test
String backend1 = "o=test-rootDSE-subordinate-naming-context-1";
String backend2 = "o=test-rootDSE-subordinate-naming-context-2";
String backendID1 = "test-rootDSE-subordinate-naming-context-1";
String backendID2 = "test-rootDSE-subordinate-naming-context-2";
try
{
TestCaseUtils.clearDataBackends();
// At this point, the list of subordinate naming context is not defined
// yet (null): any public backend should be visible. Create a backend
// with a base entry and check that the test naming context is visible.
TestCaseUtils.initializeMemoryBackend(backendID1, backend1, true);
searchPublicNamingContexts(ResultCode.SUCCESS, 1);
// Create another test backend and check that the new backend is visible
TestCaseUtils.initializeMemoryBackend(backendID2, backend2, true);
searchPublicNamingContexts(ResultCode.SUCCESS, 2);
// Now put in the list of subordinate naming context the backend1 naming context.
// This white list will prevent the backend2 to be visible.
TestCaseUtils.dsconfig(
"set-root-dse-backend-prop",
"--set", "subordinate-base-dn:" + backend1);
searchPublicNamingContexts(ResultCode.SUCCESS, 1);
// === Cleaning
// Reset the subordinate naming context list.
// Both naming context should be visible again.
TestCaseUtils.dsconfig(
"set-root-dse-backend-prop",
"--reset", "subordinate-base-dn");
searchPublicNamingContexts(ResultCode.SUCCESS, 2);
}
finally
{
// Clean the test backends. There is no more naming context.
TestCaseUtils.clearMemoryBackend(backendID1);
TestCaseUtils.clearMemoryBackend(backendID2);
searchPublicNamingContexts(ResultCode.NO_SUCH_OBJECT, 0);
}
}
/**
* Searches the list of naming contexts.
*
* @param expectedRC the expected result code
* @param expectedNamingContexts the number of expected naming contexts
*/
private void searchPublicNamingContexts(ResultCode expectedRC, int expectedNamingContexts) throws Exception
{
searchEntries("", expectedRC, expectedNamingContexts);
}
private void searchEntries(String baseDN, ResultCode expectedRC, int expectedNbEntries) throws DirectoryException
{
SearchRequest request = newSearchRequest(DN.valueOf(baseDN), SearchScope.SINGLE_LEVEL);
SearchOperation search = getRootConnection().processSearch(request);
assertEquals(search.getResultCode(), expectedRC);
if (expectedRC == ResultCode.SUCCESS)
{
assertEquals(search.getEntriesSent(), expectedNbEntries);
}
}
/**
* Searches an entry on a given connection.
*
* @param baseDN the request base DN string
* @param expectedRC the expected result code
*/
private void searchEntry(String baseDN, ResultCode expectedRC) throws Exception
{
SearchRequest request = newSearchRequest(DN.valueOf(baseDN), SearchScope.BASE_OBJECT);
SearchOperation search = getRootConnection().processSearch(request);
assertEquals(search.getResultCode(), expectedRC);
}
/**
* Creates a base entry for the given suffix.
*
* @param suffix the suffix for which the base entry is to be created
*/
private void addBaseEntry(String suffix, String namingAttribute) throws Exception
{
TestCaseUtils.addEntry(
"dn: " + suffix,
"objectClass: top",
"objectClass: organization",
"o: " + namingAttribute);
}
/**
* Adds/Deletes/Replaces an attribute in a given entry.
*
* @param baseDN the request base DN string
* @param modType the modification type (add/delete/replace)
* @param attributeName the name of the attribute to add/delete/replace
* @param attributeValue the value of the attribute to add/delete/replace
*/
private void modifyAttribute(String baseDN, ModificationType modType, String attributeName, String attributeValue)
throws Exception
{
ArrayList<Modification> mods = new ArrayList<>();
Attribute attributeToModify = Attributes.create(attributeName, attributeValue);
mods.add(new Modification(modType, attributeToModify));
ModifyOperation modifyOperation = getRootConnection().processModify(DN.valueOf(baseDN), mods);
assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
}
}