LDIFBackendTestCase.java revision 763a75aeed1a7731ddb95b99496aa7c1bf206ed0
/*
* 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 2008 Sun Microsystems, Inc.
* Portions Copyright 2014-2015 ForgeRock AS
*/
package org.opends.server.backends;
import static org.opends.server.protocols.internal.InternalClientConnection.*;
import static org.opends.server.protocols.internal.Requests.*;
import static org.testng.Assert.*;
import java.io.File;
import java.util.UUID;
import org.forgerock.opendj.ldap.ConditionResult;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.SearchScope;
import org.opends.server.TestCaseUtils;
import org.opends.server.api.Backend;
import org.opends.server.api.Backend.BackendOperation;
import org.opends.server.backends.task.Task;
import org.opends.server.backends.task.TaskState;
import org.opends.server.core.AddOperation;
import org.opends.server.core.CompareOperation;
import org.opends.server.core.DeleteOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.protocols.internal.SearchRequest;
import org.opends.server.tasks.LdifFileWriter;
import org.opends.server.tasks.TasksTestCase;
import org.opends.server.tools.LDAPModify;
import org.opends.server.tools.LDAPSearch;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Entry;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* A set of test cases for the LDIF backend.
*/
public class LDIFBackendTestCase
extends BackendTestCase
{
/**
* Ensures that the Directory Server is running and that the LDIF backend
* is populated with sample data.
*
* @throws Exception If an unexpected problem occurs.
*/
@BeforeClass
public void setUp() throws Exception
{
TestCaseUtils.startServer();
String templateFilePath = TestCaseUtils.createTempFile(
"define suffix=o=ldif",
"define numusers=25",
"",
"branch: [suffix]",
"",
"branch: ou=People,[suffix]",
"subordinateTemplate: person:[numusers]",
"",
"template: person",
"rdnAttr: uid",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"givenName: <random:alpha:6>",
"sn: <random:alpha:6>",
"cn: {givenName} {sn}",
"uid: user.<sequential:1>",
"userPassword: password");
// Create a temporary test LDIF file.
File ldifFile = File.createTempFile("import-test", ".ldif");
String resourcePath = DirectoryServer.getInstanceRoot() + File.separator +
"config" + File.separator + "MakeLDIF";
LdifFileWriter.makeLdif(ldifFile.getPath(), resourcePath, templateFilePath);
String taskDN = "ds-task-id=" + UUID.randomUUID() +
",cn=Scheduled Tasks,cn=Tasks";
TestCaseUtils.addEntry(
"dn: " + taskDN,
"objectclass: top",
"objectclass: ds-task",
"objectclass: ds-task-import",
"ds-task-class-name: org.opends.server.tasks.ImportTask",
"ds-task-import-backend-id: ldifRoot",
"ds-task-import-ldif-file: " + ldifFile.getAbsolutePath());
Task t = TasksTestCase.getCompletedTask(DN.valueOf(taskDN));
assertNotNull(t);
assertEquals(t.getTaskState(), TaskState.COMPLETED_SUCCESSFULLY);
}
/**
* Tests to ensure that add and delete operations (including subtree delete)
* work as expected.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testAddAndDelete()
throws Exception
{
// Add a number of entries to the server.
int resultCode = TestCaseUtils.applyModifications(false,
"dn: ou=dummy,o=ldif",
"changetype: add",
"objectClass: top",
"objectClass: organizationalUnit",
"ou: dummy",
"",
"dn: ou=sub1,ou=dummy,o=ldif",
"changetype: add",
"objectClass: top",
"objectClass: organizationalUnit",
"ou: sub1",
"",
"dn: ou=sub2,ou=dummy,o=ldif",
"changetype: add",
"objectClass: top",
"objectClass: organizationalUnit",
"ou: sub2",
"",
"dn: ou=sub3,ou=dummy,o=ldif",
"changetype: add",
"objectClass: top",
"objectClass: organizationalUnit",
"ou: sub3",
"",
"dn: ou=sub4,ou=dummy,o=ldif",
"changetype: add",
"objectClass: top",
"objectClass: organizationalUnit",
"ou: sub4",
"",
"dn: ou=sub5,ou=dummy,o=ldif",
"changetype: add",
"objectClass: top",
"objectClass: organizationalUnit",
"ou: sub5");
assertEquals(resultCode, 0);
// Verify that we can delete a single leaf entry.
resultCode = TestCaseUtils.applyModifications(false,
"dn: ou=sub5,ou=dummy,o=ldif",
"changetype: delete");
assertEquals(resultCode, 0);
// Verify that a default attempt to delete a non-leaf entry will fail.
String subtreeDeletePath = TestCaseUtils.createTempFile(
"dn: ou=dummy,o=ldif",
"changetype: delete");
String[] args =
{
"-h", "127.0.0.1",
"-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
"-D", "cn=Directory Manager",
"-w", "password",
"-f", subtreeDeletePath
};
resultCode = LDAPModify.mainModify(args, false, System.out, System.err);
assertEquals(resultCode, ResultCode.NOT_ALLOWED_ON_NONLEAF.intValue());
// Verify that the subtree delete will succeed if we include the subtree
// delete control in the request.
args = new String[]
{
"-h", "127.0.0.1",
"-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
"-D", "cn=Directory Manager",
"-w", "password",
"-J", "subtreeDelete",
"-f", subtreeDeletePath
};
resultCode = LDAPModify.mainModify(args, false, System.out, System.err);
assertEquals(resultCode, 0);
}
/**
* Tests an attempt to add an entry to the LDIF backend when an entry with
* the same DN already exists.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testAddAlreadyExists()
throws Exception
{
Entry e = TestCaseUtils.makeEntry(
"dn: ou=People,o=ldif",
"objectClass: top",
"objectClass: organizationalUnit",
"ou: People");
AddOperation addOperation = getRootConnection().processAdd(e);
assertEquals(addOperation.getResultCode(), ResultCode.ENTRY_ALREADY_EXISTS);
}
/**
* Tests an attempt to add an entry to the LDIF backend when the parent for
* the new entry doesn't exist.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testAddNoParent()
throws Exception
{
Entry e = TestCaseUtils.makeEntry(
"dn: ou=test,ou=doesntexist,o=ldif",
"objectClass: top",
"objectClass: organizationalUnit",
"ou: test");
AddOperation addOperation = getRootConnection().processAdd(e);
assertEquals(addOperation.getResultCode(), ResultCode.NO_SUCH_OBJECT);
assertEquals(addOperation.getMatchedDN(), DN.valueOf("o=ldif"));
}
/**
* Tests the ability to add the base entry to the backend. This will first
* perform a subtree delete to get rid of everything, then add the base entry,
* and then restore the original content.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testAddBaseEntry() throws Exception
{
assertTrue(DirectoryServer.entryExists(DN.valueOf("o=ldif")));
assertTrue(DirectoryServer.entryExists(
DN.valueOf("uid=user.1,ou=People,o=ldif")));
String path = TestCaseUtils.createTempFile(
"dn: o=ldif",
"changetype: delete");
String[] args =
{
"-h", "127.0.0.1",
"-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
"-D", "cn=Directory Manager",
"-w", "password",
"-J", "subtreeDelete",
"-f", path
};
assertEquals(LDAPModify.mainModify(args, false, System.out, System.err), 0);
assertFalse(DirectoryServer.entryExists(DN.valueOf("o=ldif")));
assertFalse(DirectoryServer.entryExists(
DN.valueOf("uid=user.1,ou=People,o=ldif")));
TestCaseUtils.addEntry(
"dn: o=ldif",
"objectClass: top",
"objectClass: organization",
"o: ldif");
assertTrue(DirectoryServer.entryExists(DN.valueOf("o=ldif")));
assertFalse(DirectoryServer.entryExists(
DN.valueOf("uid=user.1,ou=People,o=ldif")));
setUp();
assertTrue(DirectoryServer.entryExists(DN.valueOf("o=ldif")));
assertTrue(DirectoryServer.entryExists(
DN.valueOf("uid=user.1,ou=People,o=ldif")));
}
/**
* Tests to ensure that we can bind as a user contained in an LDIF backend.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testBind()
throws Exception
{
String[] args =
{
"-h", "127.0.0.1",
"-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
"-D", "uid=user.1,ou=People,o=ldif",
"-w", "password",
"-b", "o=ldif",
"-s", "base",
"(objectClass=*)"
};
assertEquals(LDAPSearch.mainSearch(args, false, System.out, System.err), 0);
}
/**
* Tests to ensure that we can perform a compare against entries in an LDIF
* backend.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testCompare() throws Exception
{
InternalClientConnection conn = getRootConnection();
CompareOperation compareOperation =
conn.processCompare("uid=user.1,ou=People,o=ldif", "uid", "user.1");
assertEquals(compareOperation.getResultCode(), ResultCode.COMPARE_TRUE);
}
/**
* Tests to ensure that we can modify entries in the LDIF backend.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testModify() throws Exception
{
String path = TestCaseUtils.createTempFile(
"dn: o=ldif",
"changetype: modify",
"replace: description",
"description: foo");
String[] args =
{
"-h", "127.0.0.1",
"-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
"-D", "cn=Directory Manager",
"-w", "password",
"-f", path
};
assertEquals(LDAPModify.mainModify(args, false, System.out, System.err), 0);
}
/**
* Tests a simple modify DN operation that targets a single leaf entry.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testSimpleModifyDN()
throws Exception
{
TestCaseUtils.addEntry(
"dn: ou=leaf before,o=ldif",
"objectClass: top",
"objectClass: organizationalUnit",
"ou: leaf before");
DN beforeDN = DN.valueOf("ou=leaf before,o=ldif");
DN afterDN = DN.valueOf("ou=leaf after,o=ldif");
assertTrue(DirectoryServer.entryExists(beforeDN));
assertFalse(DirectoryServer.entryExists(afterDN));
InternalClientConnection conn = getRootConnection();
ModifyDNOperation modifyDNOperation =
conn.processModifyDN("ou=leaf before,o=ldif", "ou=leaf after", true);
assertEquals(modifyDNOperation.getResultCode(), ResultCode.SUCCESS);
assertFalse(DirectoryServer.entryExists(beforeDN));
assertTrue(DirectoryServer.entryExists(afterDN));
DeleteOperation deleteOperation = conn.processDelete(afterDN);
assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
assertFalse(DirectoryServer.entryExists(afterDN));
}
/**
* Tests a modify DN operation in which the target entry already exists.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testModifyDNTargetAlreadyExists()
throws Exception
{
TestCaseUtils.addEntry(
"dn: ou=new entry,o=ldif",
"objectClass: top",
"objectClass: organizationalUnit",
"ou: new entry");
InternalClientConnection conn = getRootConnection();
ModifyDNOperation modifyDNOperation =
conn.processModifyDN("ou=new entry,o=ldif", "ou=People", true);
assertEquals(modifyDNOperation.getResultCode(),
ResultCode.ENTRY_ALREADY_EXISTS);
assertTrue(DirectoryServer.entryExists(DN.valueOf("ou=new entry,o=ldif")));
DeleteOperation deleteOperation = conn.processDelete("ou=new entry,o=ldif");
assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
assertFalse(DirectoryServer.entryExists(DN.valueOf("ou=new entry,o=ldif")));
}
/**
* Tests a modify DN operation that targets a single leaf entry and provides a
* new superior DN.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testModifyDNWithNewSuperior()
throws Exception
{
TestCaseUtils.addEntry(
"dn: ou=leaf before,o=ldif",
"objectClass: top",
"objectClass: organizationalUnit",
"ou: leaf before");
DN beforeDN = DN.valueOf("ou=leaf before,o=ldif");
DN afterDN = DN.valueOf("ou=leaf after,ou=People,o=ldif");
assertTrue(DirectoryServer.entryExists(beforeDN));
assertFalse(DirectoryServer.entryExists(afterDN));
InternalClientConnection conn = getRootConnection();
ModifyDNOperation modifyDNOperation =
conn.processModifyDN("ou=leaf before,o=ldif", "ou=leaf after", true,
"ou=People,o=ldif");
assertEquals(modifyDNOperation.getResultCode(), ResultCode.SUCCESS);
assertFalse(DirectoryServer.entryExists(beforeDN));
assertTrue(DirectoryServer.entryExists(afterDN));
DeleteOperation deleteOperation = conn.processDelete(afterDN);
assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
assertFalse(DirectoryServer.entryExists(afterDN));
}
/**
* Tests a modify DN operation that involves a subtree rename operation.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testModifyDNSubtreeRename()
throws Exception
{
DN beforeDN = DN.valueOf("ou=People,o=ldif");
DN afterDN = DN.valueOf("ou=Users,o=ldif");
DN childBeforeDN = DN.valueOf("uid=user.1,ou=People,o=ldif");
DN childAfterDN = DN.valueOf("uid=user.1,ou=Users,o=ldif");
assertTrue(DirectoryServer.entryExists(beforeDN));
assertFalse(DirectoryServer.entryExists(afterDN));
assertTrue(DirectoryServer.entryExists(childBeforeDN));
assertFalse(DirectoryServer.entryExists(childAfterDN));
InternalClientConnection conn = getRootConnection();
ModifyDNOperation modifyDNOperation =
conn.processModifyDN("ou=People,o=ldif", "ou=Users", true);
assertEquals(modifyDNOperation.getResultCode(), ResultCode.SUCCESS);
assertFalse(DirectoryServer.entryExists(beforeDN));
assertTrue(DirectoryServer.entryExists(afterDN));
assertFalse(DirectoryServer.entryExists(childBeforeDN));
assertTrue(DirectoryServer.entryExists(childAfterDN));
modifyDNOperation =
conn.processModifyDN("ou=Users,o=ldif", "ou=People", true);
assertTrue(DirectoryServer.entryExists(beforeDN));
assertFalse(DirectoryServer.entryExists(afterDN));
assertTrue(DirectoryServer.entryExists(childBeforeDN));
assertFalse(DirectoryServer.entryExists(childAfterDN));
}
/**
* Tests to ensure that a base-level search works as expected.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testBaseSearch() throws Exception
{
SearchRequest request = newSearchRequest(DN.valueOf("o=ldif"), SearchScope.BASE_OBJECT);
InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
assertEquals(searchOperation.getSearchEntries().size(), 1);
}
/**
* Tests to ensure that a base-level search works as expected when the filter
* doesn't match the target entry.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testBaseSearchNonMatchingFilter() throws Exception
{
InternalSearchOperation searchOperation =
getRootConnection().processSearch(newSearchRequest("o=ldif", SearchScope.BASE_OBJECT, "(o=not ldif)"));
assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
assertEquals(searchOperation.getSearchEntries().size(), 0);
}
/**
* Tests to ensure that a base-level search works as expected when the target
* entry does not exist.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testBaseSearchNoSuchEntry() throws Exception
{
DN dn = DN.valueOf("o=nonexistent2,o=nonexistent1,o=ldif");
SearchRequest request = newSearchRequest(dn, SearchScope.BASE_OBJECT);
InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
assertEquals(searchOperation.getResultCode(), ResultCode.NO_SUCH_OBJECT);
assertEquals(searchOperation.getMatchedDN(), DN.valueOf("o=ldif"));
}
/**
* Tests to ensure that a single-level search works as expected.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testSingleLevelSearch() throws Exception
{
SearchRequest request = newSearchRequest(DN.valueOf("o=ldif"), SearchScope.SINGLE_LEVEL);
InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
assertEquals(searchOperation.getSearchEntries().size(), 1);
}
/**
* Tests to ensure that subtree search operations work as expected.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testSubtreeSearch() throws Exception
{
SearchRequest request = newSearchRequest("o=ldif", SearchScope.WHOLE_SUBTREE, "(uid=user.1)");
InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
assertEquals(searchOperation.getSearchEntries().size(), 1);
}
/**
* Tests to ensure that subordinate subtree search operations work as
* expected.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testSubordinateSubtreeSearch() throws Exception
{
SearchRequest request = newSearchRequest("o=ldif", SearchScope.SUBORDINATES, "(uid=user.1)");
InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
assertEquals(searchOperation.getSearchEntries().size(), 1);
}
/**
* Tests the {@code hasSubordinates} method.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testHasSubordinates() throws Exception
{
Backend<?> b = getLDIFBackend();
assertEquals(b.hasSubordinates(DN.valueOf("o=ldif")), ConditionResult.TRUE);
assertEquals(b.hasSubordinates(DN.valueOf("uid=user.1,ou=People,o=ldif")),
ConditionResult.FALSE);
try
{
b.hasSubordinates(DN.valueOf("ou=nonexistent,o=ldif"));
fail("Expected an exception when calling hasSubordinates on a " +
"non-existent entry");
}
catch (DirectoryException de)
{
assertEquals(de.getResultCode(), ResultCode.NO_SUCH_OBJECT);
}
}
/**
* Tests the {@code numSubordinates} method.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testNumSubordinates()
throws Exception
{
Backend<?> b = getLDIFBackend();
assertEquals(b.numSubordinates(DN.valueOf("o=ldif"), false), 1);
assertEquals(b.numSubordinates(DN.valueOf("o=ldif"), true), 26);
assertEquals(b.numSubordinates(
DN.valueOf("uid=user.1,ou=People,o=ldif"), false), 0);
assertEquals(b.numSubordinates(
DN.valueOf("uid=user.1,ou=People,o=ldif"), true), 0);
try
{
b.numSubordinates(DN.valueOf("ou=nonexistent,o=ldif"), false);
fail("Expected an exception when calling numSubordinates on a " +
"non-existent entry");
}
catch (DirectoryException de)
{
assertEquals(de.getResultCode(), ResultCode.NO_SUCH_OBJECT);
}
}
/**
* Tests LDIF export functionality.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testLDIFExport() throws Exception
{
Backend<?> b = getLDIFBackend();
assertTrue(b.supports(BackendOperation.LDIF_EXPORT));
String tempFilePath = TestCaseUtils.createTempFile();
String taskDN = "ds-task-id=" + UUID.randomUUID() +
",cn=Scheduled Tasks,cn=Tasks";
TestCaseUtils.addEntry(
"dn: " + taskDN,
"objectclass: top",
"objectclass: ds-task",
"objectclass: ds-task-export",
"ds-task-class-name: org.opends.server.tasks.ExportTask",
"ds-task-export-backend-id: ldifRoot",
"ds-task-export-ldif-file: " + tempFilePath);
Task t = TasksTestCase.getCompletedTask(DN.valueOf(taskDN));
assertNotNull(t);
assertEquals(t.getTaskState(), TaskState.COMPLETED_SUCCESSFULLY);
}
/**
* Tests a number of miscellaneous backend methods.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test
public void testMiscellaneousBackendMethods()
throws Exception
{
LDIFBackend b = getLDIFBackend();
assertTrue(b.getEntryCount() > 0);
assertFalse(b.supports(BackendOperation.BACKUP));
try
{
b.createBackup(null);
fail("Expected an exception when calling createBackup");
} catch (DirectoryException de) {}
try
{
b.removeBackup(null, null);
fail("Expected an exception when calling removeBackup");
} catch (DirectoryException de) {}
assertFalse(b.supports(BackendOperation.RESTORE));
try
{
b.restoreBackup(null);
fail("Expected an exception when calling restoreBackup");
} catch (DirectoryException de) {}
assertNotNull(b.getClassName());
assertNotNull(b.getAlerts());
assertFalse(b.getAlerts().isEmpty());
}
private LDIFBackend getLDIFBackend()
{
Backend<?> b = DirectoryServer.getBackend("ldifRoot");
assertNotNull(b);
assertTrue(b instanceof LDIFBackend);
return (LDIFBackend) b;
}
}