mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Fabio Pistolesi
06.43.2015 e7d1a63f1b251ee4139e50877d33d308d8ec2149
OPENDJ-1740 CR-5939 Develop unit tests for pluggable backend and a refactoring on an existing test.

Add unit tests for basic operations of a pluggable backend and a test for PersistIt storage.
2 files added
1 files modified
965 ■■■■■ changed files
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/admin/ValidateConfigDefinitionsTest.java 20 ●●●● patch | view | raw | blame | history
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/pluggable/PluggableBackendImplTestCase.java 857 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/pluggable/persistit/PersistitTestCase.java 88 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/admin/ValidateConfigDefinitionsTest.java
@@ -22,7 +22,7 @@
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 *      Portions copyright 2011-2015 ForgeRock AS
 */
package org.opends.server.admin;
@@ -74,10 +74,10 @@
  // Exceptions to config objects having a differnt objectclass
  private static final List<String> CLASS_OBJECT_CLASS_EXCEPTIONS =
          Arrays.asList(new String[]{
          Arrays.asList(
                  "org.opends.server.admin.std.meta.RootCfgDefn",
                  "org.opends.server.admin.std.meta.GlobalCfgDefn",
          });
                  "org.opends.server.admin.std.meta.GlobalCfgDefn"
          );
  @Test(dataProvider="enumrateManageObjectDefns")
@@ -114,21 +114,21 @@
  // Exceptions to properties ending in -class being exactly 'java-class'.
  private static final List<String> CLASS_PROPERTY_EXCEPTIONS =
          Arrays.asList(new String[]{
          Arrays.asList(
                  // e.g. "prop-name-ending-with-class"
          });
          );
  // Exceptions to properties ending in -enabled being exactly 'enabled'.
  private static final List<String> ENABLED_PROPERTY_EXCEPTIONS =
          Arrays.asList(new String[]{
          Arrays.asList(
                  "index-filter-analyzer-enabled",
                  "subordinate-indexes-enabled"
                  // e.g. "prop-name-ending-with-enabled"
          });
          );
  // Exceptions to properties not starting with the name of their config object
  private static final List<String> OBJECT_PREFIX_PROPERTY_EXCEPTIONS =
          Arrays.asList(new String[]{
          Arrays.asList(
                  "backend-id",
                  "plugin-type",
                  "replication-server-id",
@@ -137,7 +137,7 @@
                  "workflow-element-id",
                  "workflow-element"
                  // e.g. "prop-name-starting-with-object-prefix"
          });
          );
  private void validatePropertyDefinition(AbstractManagedObjectDefinition<?, ?> objectDef,
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/pluggable/PluggableBackendImplTestCase.java
New file
@@ -0,0 +1,857 @@
/*
 * 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 2015 ForgeRock AS
 */
package org.opends.server.backends.pluggable;
import static org.forgerock.opendj.ldap.ModificationType.ADD;
import static org.opends.server.protocols.internal.InternalClientConnection.getRootConnection;
import static org.opends.server.protocols.internal.Requests.newSearchRequest;
import static org.opends.server.types.Attributes.create;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import org.assertj.core.api.Assertions;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.ConditionResult;
import org.forgerock.opendj.ldap.SearchScope;
import org.opends.server.DirectoryServerTestCase;
import org.opends.server.TestCaseUtils;
import org.opends.server.core.DirectoryServer;
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.tools.makeldif.TemplateFile;
import org.opends.server.types.AttributeType;
import org.opends.server.types.BackupConfig;
import org.opends.server.types.BackupDirectory;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Entry;
import org.opends.server.types.IndexType;
import org.opends.server.types.LDIFExportConfig;
import org.opends.server.types.LDIFImportConfig;
import org.opends.server.types.Modification;
import org.opends.server.types.RestoreConfig;
import org.opends.server.types.SearchResultEntry;
import org.opends.server.workflowelement.localbackend.LocalBackendSearchOperation;
import org.testng.Reporter;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
 * BackendImpl Tester.
 */
@SuppressWarnings("javadoc")
@Test(groups = { "precommit", "pluggablebackend" }, sequential = true)
public abstract class PluggableBackendImplTestCase extends DirectoryServerTestCase
{
  protected BackendImpl backend;
  protected List<Entry> topEntries;
  protected List<Entry> entries;
  protected List<Entry> workEntries;
  protected DN testBaseDN;
  protected DN dnToMod;
  protected DN dnToDel;
  protected DN searchDN;
  protected DN badEntryDN;
  protected String[] ldifTemplate;
  protected int ldifNumberOfEntries;
  protected String backupID;
  protected String[] backendIndexes = { "sn" };
  protected String[] backendVlvIndexes = {};
  private AttributeType modifyAttribute;
  private final ByteString modifyValue = ByteString.valueOf("foo");
  private String backupPath;
  private BackupDirectory backupDirectory;
  /**
   * Configures a backend for the specified backend
   *
   * @param homeDirName
   *          Directory where database file live
   * @param testBaseDN
   *          Root DN for the DIT
   * @return a backend object.
   */
  protected abstract BackendImpl createBackend() throws Exception;
  @BeforeClass
  public void setUp() throws Exception
  {
    // Need the schema to be available, so make sure the server is started.
    TestCaseUtils.startServer();
    testBaseDN = DN.valueOf("dc=test,dc=com");
    backend = createBackend();
    backend.initializeBackend();
    topEntries = TestCaseUtils.makeEntries(
                "dn: " + testBaseDN,
                "objectclass: top",
                "objectclass: domain",
                "",
                "dn: ou=People," + testBaseDN,
                "objectclass: top",
                "objectclass: organizationalUnit",
                "ou: People");
    entries = TestCaseUtils.makeEntries(
                "dn: uid=user.0,ou=People," + testBaseDN,
                "objectClass: top",
                "objectClass: person",
                "objectClass: organizationalPerson",
                "objectClass: inetOrgPerson",
                "givenName: Aaccf",
                "sn: Amar",
                "cn: Aaccf Amar",
                "initials: AQA",
                "employeeNumber: 0",
                "uid: user.0",
                "mail: user.0@example.com",
                "userPassword: password",
                "telephoneNumber: 380-535-2354",
                "homePhone: 707-626-3913",
                "pager: 456-345-7750",
                "mobile: 366-674-7274",
                "street: 99262 Eleventh Street",
                "l: Salem",
                "st: NM",
                "postalCode: 36530",
                "postalAddress: Aaccf Amar$99262 Eleventh Street$Salem, NM  36530",
                "description: This is the description for Aaccf Amar.",
                "",
                "dn: uid=user.1,ou=People," + testBaseDN,
                "objectClass: top",
                "objectClass: person",
                "objectClass: organizationalPerson",
                "objectClass: inetOrgPerson",
                "givenName: Aaren",
                "givenName;lang-fr: test2",
                "givenName;lang-cn: test2",
                "givenName;lang-es: test3",
                "sn: Atp",
                "cn: Aaren Atp",
                "initials: APA",
                "employeeNumber: 1",
                "uid: user.1",
                "mail: user.1@example.com",
                "userPassword: password",
                "telephoneNumber: 643-278-6134",
                "homePhone: 546-786-4099",
                "pager: 508-261-3187",
                "mobile: 377-267-7824",
                "carLicense: 377-267-7824",
                "street: 78113 Fifth Street",
                "l: Chico",
                "st: TN",
                "postalCode: 72322",
                "postalAddress: Aaren Atp$78113 Fifth Street$Chico, TN  72322",
                "description: This is the description for Aaren Atp.",
                "",
                "dn: uid=user.2,ou=People," + testBaseDN,
                "objectClass: top",
                "objectClass: person",
                "objectClass: organizationalPerson",
                "objectClass: inetOrgPerson",
                "givenName: Aarika",
                "sn: Atpco",
                "cn: Aarika Atpco",
                "initials: ARA",
                "employeeNumber: 2",
                "uid: user.2",
                "mail: user.2@example.com",
                "userPassword: password",
                "telephoneNumber: 547-504-3498",
                "homePhone: 955-899-7308",
                "pager: 710-832-9316",
                "mobile: 688-388-4525",
                "carLicense: 688-388-4525",
                "street: 59208 Elm Street",
                "l: Youngstown",
                "st: HI",
                "postalCode: 57377",
                "postalAddress: Aarika Atpco$59208 Elm Street$Youngstown, HI  57377",
                "description: This is the description for Aarika Atpco.",
                "",
                "dn: uid=user.3,ou=People," + testBaseDN,
                "objectClass: top",
                "objectClass: person",
                "objectClass: organizationalPerson",
                "objectClass: inetOrgPerson",
                "givenName: Aaron",
                "sn: Atrc",
                "cn: Aaron Atrc",
                "initials: AIA",
                "employeeNumber: 3",
                "uid: user.3",
                "mail: user.3@example.com",
                "userPassword: password",
                "telephoneNumber: 128-108-4939",
                "homePhone: 512-782-9966",
                "pager: 322-646-5118",
                "mobile: 360-957-9137",
                "carLicense: 360-957-9137",
                "street: 25074 Hill Street",
                "l: Toledo",
                "st: OR",
                "postalCode: 55237",
                "postalAddress: Aaron Atrc$25074 Hill Street$Toledo, OR  55237",
                "description: This is the description for Aaron Atrc.",
                "",
                "dn: uid=user.4,ou=People," + testBaseDN,
                "objectClass: top",
                "objectClass: person",
                "objectClass: organizationalPerson",
                "objectClass: inetOrgPerson",
                "givenName: Aartjan",
                "sn: Aalders",
                "cn: Aartjan Aalders",
                "initials: ALA",
                "employeeNumber: 4",
                "uid: user.4",
                "mail: user.4@example.com",
                "userPassword: password",
                "telephoneNumber: 981-148-3303",
                "homePhone: 196-877-2684",
                "pager: 910-998-4607",
                "mobile: 123-239-8262",
                "carLicense: 123-239-8262",
                "street: 81512 Sunset Street",
                "l: Chattanooga",
                "st: WV",
                "postalCode: 29530",
                "postalAddress: Aartjan Aalders$81512 Sunset Street$Chattanooga, WV  29530",
                "description: This is the description for Aartjan Aalders.",
                "",
                "dn: uid=user.5,ou=People," + testBaseDN,
                "objectClass: top",
                "objectClass: person",
                "objectClass: organizationalPerson",
                "objectClass: inetOrgPerson",
                "givenName: Abagael",
                "sn: Aasen",
                "cn: Abagael Aasen",
                "initials: AKA",
                "employeeNumber: 5",
                "uid: user.5",
                "mail: user.5@example.com",
                "userPassword: password",
                "telephoneNumber: 930-493-2391",
                "homePhone: 078-254-3960",
                "pager: 281-936-8197",
                "mobile: 559-822-7712",
                "carLicense: 559-822-7712",
                "street: 31988 Central Street",
                "l: Chico",
                "st: MS",
                "postalCode: 20135",
                "postalAddress: Abagael Aasen$31988 Central Street$Chico, MS  20135",
                "description: This is the description for Abagael Aasen.",
                "",
                "dn: uid=user.6,ou=People," + testBaseDN,
                "objectClass: top",
                "objectClass: person",
                "objectClass: organizationalPerson",
                "objectClass: inetOrgPerson",
                "givenName: Abagail",
                "sn: Abadines",
                "cn: Abagail Abadines",
                "initials: AQA",
                "employeeNumber: 6",
                "uid: user.6",
                "mail: user.6@example.com",
                "userPassword: password",
                "telephoneNumber: 110-761-3861",
                "homePhone: 459-123-0553",
                "pager: 799-151-2688",
                "mobile: 953-582-7252",
                "carLicense: 953-582-7252",
                "street: 60100 Dogwood Street",
                "l: Hartford",
                "st: NE",
                "postalCode: 79353",
                "postalAddress: Abagail Abadines$60100 Dogwood Street$Hartford, NE  79353",
                "description: This is the description for Abagail Abadines.",
                "",
                "dn: uid=user.7,ou=People," + testBaseDN,
                "objectClass: top",
                "objectClass: person",
                "objectClass: organizationalPerson",
                "objectClass: inetOrgPerson",
                "givenName: Abahri",
                "sn: Abazari",
                "cn: Abahri Abazari",
                "initials: AXA",
                "employeeNumber: 7",
                "uid: user.7",
                "mail: user.7@example.com",
                "userPassword: password",
                "telephoneNumber: 594-537-4292",
                "homePhone: 174-724-6390",
                "pager: 733-217-8194",
                "mobile: 879-706-0172",
                "carLicense: 879-706-0172",
                "street: 77693 Oak Street",
                "l: Philadelphia",
                "st: MN",
                "postalCode: 78550",
                "postalAddress: Abahri Abazari$77693 Oak Street$Philadelphia, MN  78550",
                "description: This is the description for Abahri Abazari.",
                "",
                "dn: uid=user.8,ou=People," + testBaseDN,
                "objectClass: top",
                "objectClass: person",
                "objectClass: organizationalPerson",
                "objectClass: inetOrgPerson",
                "givenName: Abbas",
                "sn: Abbatantuono",
                "cn: Abbas Abbatantuono",
                "initials: AVA",
                "employeeNumber: 8",
                "uid: user.8",
                "mail: user.8@example.com",
                "userPassword: password",
                "telephoneNumber: 246-674-8407",
                "homePhone: 039-769-3372",
                "pager: 226-950-2371",
                "mobile: 587-709-2996",
                "carLicense: 587-709-2996",
                "street: 23230 Hill Street",
                "l: Little Rock",
                "st: AR",
                "",
                "dn: uid=user.9,ou=People," + testBaseDN,
                "objectClass: top",
                "objectClass: person",
                "objectClass: organizationalPerson",
                "objectClass: inetOrgPerson",
                "givenName: Abbe",
                "sn: Abbate",
                "cn: Abbe Abbate",
                "initials: AWA",
                "employeeNumber: 9",
                "uid: user.9",
                "mail: user.9@example.com",
                "userPassword: password",
                "telephoneNumber: 205-805-3357",
                "homePhone: 770-780-5917",
                "pager: 537-074-8005",
                "mobile: 120-204-7597",
                "carLicense: 120-204-7597",
                "street: 47952 Center Street",
                "l: Butte",
                "st: TN",
                "postalCode: 69384",
                "postalAddress: Abbe Abbate$47952 Center Street$Butte, TN  69384",
                "description: This is the description for Abbe Abbate.",
                "",
                "dn: uid=user.10,ou=People," + testBaseDN,
                "objectClass: top",
                "objectClass: person",
                "objectClass: organizationalPerson",
                "objectClass: inetOrgPerson",
                "givenName: Abbey",
                "sn: Abbie",
                "cn: Abbey Abbie",
                "initials: AZA",
                "employeeNumber: 10",
                "uid: user.10",
                "mail: user.10@example.com",
                "userPassword: password",
                "telephoneNumber: 457-819-0832",
                "homePhone: 931-305-5452",
                "pager: 118-165-7194",
                "mobile: 553-729-5572",
                "carLicense: 553-729-5572",
                "street: 54262 Highland Street",
                "l: Spartanburg",
                "st: PA",
                "postalCode: 38151",
                "postalAddress: Abbey Abbie$54262 Highland Street$Spartanburg, PA  38151",
                "description: This is the description for Abbey Abbie.",
                "",
                "dn: uid=user.539,ou=People," + testBaseDN,
                "objectClass: top",
                "objectClass: person",
                "objectClass: organizationalPerson",
                "objectClass: inetOrgPerson",
                "givenName: Ardyth",
                "sn: Bainton",
                "cn: Ardyth Bainton",
                "initials: AIB",
                "employeeNumber: 539",
                "uid: user.539",
                "mail: user.539@example.com",
                "userPassword: password",
                "telephoneNumber: 641-433-7404",
                "homePhone: 524-765-8780",
                "pager: 985-331-1308",
                "mobile: 279-423-0188",
                "carLicense: 279-423-0188",
                "street: 81170 Taylor Street",
                "l: Syracuse",
                "st: WV",
                "postalCode: 93507",
                "postalAddress: Ardyth Bainton$81170 Taylor Street$Syracuse, WV  93507",
                "description: This is the description for Ardyth Bainton.");
    workEntries = TestCaseUtils.makeEntries(
                "dn: uid=user.11,ou=People," + testBaseDN,
                "objectClass: top",
                "objectClass: person",
                "objectClass: organizationalPerson",
                "objectClass: inetOrgPerson",
                "givenName: Annalee",
                "sn: Avard",
                "cn: Annalee Avard",
                "initials: ANA",
                "employeeNumber: 11",
                "uid: user.11",
                "mail: user.11@example.com",
                "userPassword: password",
                "telephoneNumber: 875-335-2712",
                "homePhone: 181-995-6635",
                "pager: 586-905-4185",
                "mobile: 826-857-7592",
                "carLicense: 826-857-7592",
                "street: 46168 Mill Street",
                "l: Charleston",
                "st: CO",
                "postalCode: 60948",
                "postalAddress: Annalee Avard$46168 Mill Street$Charleston, CO  60948",
                "description: This is the description for Annalee Avard.",
                "",
                "dn: uid=user.12,ou=People," + testBaseDN,
                "objectClass: top",
                "objectClass: person",
                "objectClass: organizationalPerson",
                "objectClass: inetOrgPerson",
                "givenName: Andaree",
                "sn: Asawa",
                "cn: Andaree Asawa",
                "initials: AEA",
                "employeeNumber: 12",
                "uid: user.12",
                "mail: user.12@example.com",
                "userPassword: password",
                "telephoneNumber: 399-788-7334",
                "homePhone: 798-076-5683",
                "pager: 034-026-9411",
                "mobile: 948-743-9197",
                "carLicense: 948-743-9197",
                "street: 81028 Forest Street",
                "l: Wheeling",
                "st: IA",
                "postalCode: 60905",
                "postalAddress: Andaree Asawa$81028 Forest Street$Wheeling, IA  60905",
                "description: This is the description for Andaree Asawa.");
    dnToMod = workEntries.get(0).getName();
    dnToDel = workEntries.get(1).getName();
    searchDN = entries.get(8).getName();
    badEntryDN = testBaseDN.child(DN.valueOf("ou=bogus")).child(DN.valueOf("ou=dummy"));
    backupID = "backupID1";
    ldifNumberOfEntries = 20;
    ldifTemplate = new String [] {
      "define suffix=" + testBaseDN,
      "define maildomain=" + testBaseDN,
      "define numusers = " + ldifNumberOfEntries,
      "",
      "branch: [suffix]",
      "objectClass: domain",
      "",
      "branch: ou=People,[suffix]",
      "objectClass: organizationalUnit",
      "subordinateTemplate: person:[numusers]",
      "",
      "template: person",
      "rdnAttr: uid",
      "objectClass: top",
      "objectClass: person",
      "objectClass: organizationalPerson",
      "objectClass: inetOrgPerson",
      "givenName: ABOVE LIMIT",
      "sn: <last>",
      "cn: {givenName} {sn}",
      "initials: {givenName:1}<random:chars:ABCDEFGHIJKLMNOPQRSTUVWXYZ:1>{sn:1}",
      "employeeNumber: <sequential:0>",
      "uid: user.{employeeNumber}",
      "mail: {uid}@[maildomain]",
      "userPassword: password",
      "telephoneNumber: <random:telephone>",
      "homePhone: <random:telephone>",
      "pager: <random:telephone>",
      "mobile: <random:telephone>",
      "street: <random:numeric:5> <file:streets> Street",
      "l: <file:cities>",
      "st: <file:states>",
      "postalCode: <random:numeric:5>",
      "postalAddress: {cn}${street}${l}, {st}  {postalCode}",
      "description: This is the description for {cn}.",
      ""};
    // Add suffix and barnch entries
    ldifNumberOfEntries += 2;
  }
  @AfterClass
  public void cleanUp() throws Exception
  {
    try
    {
      backend.removeBackup(backupDirectory, backupID);
    }
    catch (DirectoryException ignore)
    {
      /*
       *  Due to test sequencing (Import, backup, restore, export) in case of intermediate failure
       *  Backup may or may not be present. -> ignore.
       */
      Reporter.log(ignore.getMessage(), true);
    }
    finally
    {
      backend.finalizeBackend();
      backend = null;
    }
  }
  public void testAdd() throws Exception
  {
    addEntriesToBackend(topEntries);
    addEntriesToBackend(entries);
    addEntriesToBackend(workEntries);
  }
  /**
   * Helper for add entries in a backend.
   * @throws Exception
   */
  private void addEntriesToBackend(List<Entry> entries) throws Exception
  {
    for (Entry newEntry : entries)
    {
      backend.addEntry(newEntry, null);
    }
  }
  @Test(expectedExceptions = DirectoryException.class)
  public void testAddNoParent() throws Exception
  {
    Entry newEntry = TestCaseUtils.makeEntry("dn: " + badEntryDN, "objectclass: ou", "");
    backend.addEntry(newEntry, null);
  }
  @Test(dependsOnMethods = "testAdd")
  public void testUtilityAPIs()
  {
    assertEquals(backend.getEntryCount(), getTotalNumberOfLDIFEntries());
    assertFalse(backend.isIndexed(modifyAttribute, IndexType.EQUALITY));
    assertTrue(backend.isIndexed(DirectoryServer.getAttributeType(backendIndexes[0]), IndexType.EQUALITY));
  }
  private int getTotalNumberOfLDIFEntries()
  {
    return topEntries.size() + entries.size() + workEntries.size();
  }
  @Test(dependsOnMethods = "testAdd")
  public void testHasSubordinates() throws Exception
  {
    assertEquals(backend.hasSubordinates(testBaseDN), ConditionResult.TRUE,
        "Base DN should have subordinates.");
    // Testing ConditionResult.UNDEFINED needs either no entry container or a big DIT...
    assertEquals(backend.hasSubordinates(DN.valueOf("dc=a")), ConditionResult.UNDEFINED,
        "Subordinates query on unknown baseDN should return UNDEFINED.");
    assertEquals(backend.numSubordinates(testBaseDN, false), 1);
    assertEquals(backend.numSubordinates(testBaseDN, true), getTotalNumberOfLDIFEntries() - 1, "Wrong DIT count.");
    assertEquals(backend.hasSubordinates(searchDN), ConditionResult.FALSE,
        "Leaf entry should not have any subordinates.");
  }
  private List<SearchResultEntry> runSearch(SearchRequest request, boolean useInternalConnection) throws Exception
  {
    InternalClientConnection conn = getRootConnection();
    if (useInternalConnection)
    {
      InternalSearchOperation search = conn.processSearch(request);
      return search.getSearchEntries();
    }
    else
    {
      InternalSearchOperation search = new InternalSearchOperation(conn, -1, -1, request);
      backend.search(new LocalBackendSearchOperation(search));
      return search.getSearchEntries();
    }
  }
  @Test(dependsOnMethods = { "testAdd", "testModifyEntry", "testRenameEntry", "testDeleteAlreadyDeletedEntry" })
  public void testBaseSearch() throws Exception
  {
    baseSearch(false);
    baseSearch(true);
  }
  private void baseSearch(boolean useInternalConnection) throws Exception
  {
    SearchRequest request = newSearchRequest(testBaseDN, SearchScope.BASE_OBJECT, "objectclass=*");
    List<SearchResultEntry> result = runSearch(request, useInternalConnection);
    assertEquals(result.size(), 1, "Base Search should return only one Entry");
    assertEquals(result.get(0).getName(), testBaseDN, "Base Search on the suffix should return the suffix itself");
  }
  @Test(dependsOnMethods = { "testAdd", "testModifyEntry", "testRenameEntry", "testDeleteAlreadyDeletedEntry" })
  public void testOneLevelSearch() throws Exception
  {
    oneLevelSearch(false);
    oneLevelSearch(true);
  }
  private void oneLevelSearch(boolean useInternalConnection) throws Exception
  {
    SearchRequest request = newSearchRequest(testBaseDN, SearchScope.SINGLE_LEVEL, "objectclass=*");
    List<SearchResultEntry> result = runSearch(request, useInternalConnection);
    assertEquals(result.size(), 1, "One Level search should return a single child entry");
    SearchResultEntry resEntry = result.get(0);
    assertEquals(topEntries.get(1).getName(), resEntry.getName(),
        "One Level search should return the expected child");
  }
  @Test(dependsOnMethods = { "testAdd", "testModifyEntry", "testRenameEntry", "testDeleteAlreadyDeletedEntry" })
  public void testSubTreeSearch() throws Exception
  {
    subTreeSearch(false);
    subTreeSearch(true);
  }
  private void subTreeSearch(boolean useInternalConnection) throws Exception
  {
    SearchRequest request = newSearchRequest(testBaseDN, SearchScope.WHOLE_SUBTREE, "objectclass=*");
    List<SearchResultEntry> result = runSearch(request, useInternalConnection);
    // Sum of all entry sets minus a delete
    assertEquals(result.size(), getTotalNumberOfLDIFEntries() - 1,
        "Subtree search should return a correct number of entries");
  }
  @Test(dependsOnMethods = { "testAdd", "testModifyEntry", "testRenameEntry", "testDeleteAlreadyDeletedEntry" })
  public void testUserEntrySearch() throws Exception
  {
    userEntrySearch(false);
    userEntrySearch(true);
  }
  private void userEntrySearch(boolean useInternalConnection) throws Exception
  {
    SearchRequest request = newSearchRequest(searchDN, SearchScope.BASE_OBJECT, "objectclass=*");
    List<SearchResultEntry> result = runSearch(request, useInternalConnection);
    assertEquals(result.size(), 1, "User entry search should return a single child entry");
    assertEquals(searchDN, result.get(0).getName(), "User entry search should return the expected entry");
  }
  @Test(dependsOnMethods = { "testAdd", "testModifyEntry", "testRenameEntry", "testDeleteAlreadyDeletedEntry" })
  public void testGetEntry() throws Exception
  {
    Assertions.assertThat(getDbEntries(entries)).isEqualTo(entries);
  }
  private List<Entry> getDbEntries(List<Entry> entries) throws DirectoryException
  {
    List<Entry> result = new ArrayList<Entry>(entries.size());
    for (Entry currentEntry : entries)
    {
      Entry dbEntry = backend.getEntry(currentEntry.getName());
      result.add(filterOperationalAttributes(dbEntry));
    }
    return result;
  }
  private Entry filterOperationalAttributes(Entry e)
  {
    return new Entry(e.getName(), e.getObjectClasses(), e.getUserAttributes(), null);
  }
  @Test(dependsOnMethods = { "testAdd", "testModifyEntry" })
  public void testRenameEntry() throws Exception
  {
    // Move the entire subtree to another name and move it back.
    DN prevDN = DN.valueOf("ou=People," + testBaseDN);
    DN newDN = DN.valueOf("ou=users," + testBaseDN);
    Entry renameEntry = backend.getEntry(prevDN);
    renameEntry.setDN(newDN);
    backend.renameEntry(prevDN, renameEntry, null);
    Entry dbEntry = backend.getEntry(newDN);
    assertEquals(dbEntry.getName(), newDN, "Renamed entry is missing.");
    renameEntry.setDN(prevDN);
    backend.renameEntry(newDN, renameEntry, null);
    dbEntry = backend.getEntry(prevDN);
    assertEquals(dbEntry.getName(), prevDN, "Original entry has not been renamed");
  }
  @Test(dependsOnMethods = "testAdd")
  public void testModifyEntry() throws Exception
  {
    Entry oldEntry = workEntries.get(0);
    Entry newEntry = oldEntry.duplicate(false);
    modifyAttribute = DirectoryServer.getAttributeType("jpegphoto");
    newEntry.applyModifications(Arrays.asList(new Modification(ADD, create(modifyAttribute, modifyValue))));
    backend.replaceEntry(oldEntry, newEntry, null);
    assertTrue(backend.getEntry(oldEntry.getName()).hasValue(modifyAttribute, null, modifyValue));
  }
  @Test(dependsOnMethods = { "testAdd", "testRenameEntry", "testHasSubordinates" })
  public void testDeleteEntry() throws Exception
  {
    deleteEntry(dnToDel);
  }
  @Test(dependsOnMethods = "testDeleteEntry", expectedExceptions = DirectoryException.class)
  public void testDeleteAlreadyDeletedEntry() throws Exception
  {
    deleteEntry(dnToDel);
  }
  private void deleteEntry(DN dn) throws Exception
  {
    backend.deleteEntry(dn, null);
    assertNull(backend.getEntry(workEntries.get(1).getName()));
  }
  @Test(dependsOnMethods = { "testBaseSearch", "testOneLevelSearch", "testSubTreeSearch", "testUserEntrySearch" })
  public void testImportLDIF() throws Exception
  {
    assertTrue(backend.supportsLDIFImport(), "Import not supported");
    // Import wants the backend to be configured but not initialized. Finalizing resets the status.
    backend.finalizeBackend();
    assertNotNull(ldifTemplate, "Import requires an LDIF template");
    String makeLDIFPath =
        System.getProperty(TestCaseUtils.PROPERTY_BUILD_ROOT) + File.separator + "resource" + File.separator
        + "MakeLDIF";
    TemplateFile templateFile = new TemplateFile(makeLDIFPath, new Random());
    templateFile.parse(ldifTemplate, null);
    ByteArrayOutputStream rejectedEntries = new ByteArrayOutputStream();
    LDIFImportConfig importConf = new LDIFImportConfig(templateFile);
    importConf.setInvokeImportPlugins(true);
    importConf.setClearBackend(true);
    importConf.writeRejectedEntries(rejectedEntries);
    try {
      backend.importLDIF(importConf);
    }
    finally {
      importConf.close();
    }
    assertEquals(rejectedEntries.size(), 0, "No entries should be rejected");
    backend.initializeBackend();
    assertEquals(backend.getEntryCount(), ldifNumberOfEntries, "Not enough entries in DIT.");
  }
  @Test(dependsOnMethods = {"testImportLDIF"})
  public void testPreloadEntryCache()
  {
    // There is no backend.isPreloadSupported(), so try and if it fails, just let it go.
    try
    {
      backend.preloadEntryCache();
    }
    catch (UnsupportedOperationException uoe)
    {
      Reporter.log("Skipping unsupported Cache Preload", true);
    }
  }
  @Test(dependsOnMethods = "testPreloadEntryCache")
  public void testBackup() throws Exception
  {
    assertEquals(backend.supportsBackup(), true, "Skip Backup");
    assertNotNull(backupID, "Need to setup a backupID");
    backupPath = TestCaseUtils.createTemporaryDirectory("backup").getAbsolutePath();
    backupDirectory = new BackupDirectory(backupPath, testBaseDN);
    BackupConfig backupConf = new BackupConfig(backupDirectory, backupID, false);
    backupConf.setFilesToBackupFilter(backend.getRootContainer().getStorage().getFilesToBackupFilter());
    backend.createBackup(backupConf);
  }
  @Test(dependsOnMethods = "testBackup")
  public void testRestore() throws Exception
  {
    assertTrue(backend.supportsRestore(), "Skip Restore");
    backend.restoreBackup(new RestoreConfig(backupDirectory, backupID, true));
  }
  @Test(dependsOnMethods = "testRestore")
  public void testExportLDIF() throws Exception
  {
    assertTrue(backend.supportsLDIFExport(), "Export not supported");
    ByteArrayOutputStream ldifData = new ByteArrayOutputStream();
    LDIFExportConfig exportConfig = new LDIFExportConfig(ldifData);
    exportConfig.setIncludeOperationalAttributes(true);
    exportConfig.setIncludeVirtualAttributes(true);
    try
    {
      backend.exportLDIF(exportConfig);
    }
    finally
    {
      exportConfig.close();
    }
    String ldifString = ldifData.toString();
    assertEquals(ldifString.contains(testBaseDN.toString()), true, "Export without rootDN");
    assertEquals(ldifString.contains(searchDN.toString()), true, "Export without rootDN");
  }
}
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/pluggable/persistit/PersistitTestCase.java
New file
@@ -0,0 +1,88 @@
/*
 * 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 2015 ForgeRock AS
 */
package org.opends.server.backends.pluggable.persistit;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertTrue;
import org.forgerock.opendj.config.server.ConfigException;
import org.opends.server.TestCaseUtils;
import org.opends.server.admin.std.meta.BackendIndexCfgDefn.IndexType;
import org.opends.server.admin.std.server.BackendIndexCfg;
import org.opends.server.admin.std.server.PersistitBackendCfg;
import org.opends.server.admin.std.server.PluggableBackendCfg;
import org.opends.server.backends.persistit.PitBackend;
import org.opends.server.backends.pluggable.PluggableBackendImplTestCase;
import org.opends.server.core.DirectoryServer;
import org.testng.annotations.Test;
/**
 * PersistIt Tester.
 */
public class PersistitTestCase extends PluggableBackendImplTestCase
{
  @Test
  public void testPersistitCfg() throws Exception
  {
    assertTrue(backend.getRootContainer().isValid());
  }
  @Override
  public PitBackend createBackend() throws Exception
  {
    PluggableBackendCfg backendCfg = createBackendCfg();
    PitBackend b = new PitBackend();
    b.setBackendID(backendCfg.getBackendId());
    b.configureBackend((PersistitBackendCfg)backendCfg);
    return b;
  }
  private PluggableBackendCfg createBackendCfg() throws ConfigException
  {
    String homeDirName = "pdb_test";
    PersistitBackendCfg backendCfg = mock(PersistitBackendCfg.class);
    when(backendCfg.getBackendId()).thenReturn("persTest" + homeDirName);
    when(backendCfg.getDBDirectory()).thenReturn(homeDirName);
    when(backendCfg.getDBDirectoryPermissions()).thenReturn("755");
    when(backendCfg.getDBCacheSize()).thenReturn(0L);
    when(backendCfg.getDBCachePercent()).thenReturn(20);
    when(backendCfg.isSubordinateIndexesEnabled()).thenReturn(true);
    when(backendCfg.getBaseDN()).thenReturn(TestCaseUtils.newSortedSet(testBaseDN));
    when(backendCfg.dn()).thenReturn(testBaseDN);
    when(backendCfg.listBackendIndexes()).thenReturn(backendIndexes);
    when(backendCfg.listBackendVLVIndexes()).thenReturn(backendVlvIndexes);
    BackendIndexCfg indexCfg = mock(BackendIndexCfg.class);
    when(indexCfg.getIndexType()).thenReturn(TestCaseUtils.newSortedSet(IndexType.PRESENCE, IndexType.EQUALITY));
    when(indexCfg.getAttribute()).thenReturn(DirectoryServer.getAttributeType(backendIndexes[0]));
    when(backendCfg.getBackendIndex(backendIndexes[0])).thenReturn(indexCfg);
    return backendCfg;
  }
}