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

boli
31.38.2007 ee0fbff002e17a56aca09cb8dc7da0f4fe20ad6e

This fixes serveral issues LDIF import and VLV features:
- Added the ability to use both a backend ID and include branch arguments for LDIF imports
(Issue 1971)
- Fixed incorrect search scope enum in the VLV index configuration
- Added unit tests for partial LDIF imports
- Fixed issue where using overlapping include branches during an import would result in a ConcurrentModificationException (Issue 2039)

10 files modified
645 ■■■■ changed files
opends/src/admin/defn/org/opends/server/admin/std/VLVJEIndexConfiguration.xml 6 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/jeb/AttributeIndex.java 2 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/jeb/ImportJob.java 12 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/jeb/VLVIndex.java 16 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/messages/JebMessages.java 7 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tasks/ImportTask.java 214 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/ImportLDIF.java 29 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestImportJob.java 102 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/tasks/TestImportAndExport.java 221 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/tools/ImportLDIFTestCase.java 36 ●●●●● patch | view | raw | blame | history
opends/src/admin/defn/org/opends/server/admin/std/VLVJEIndexConfiguration.xml
@@ -94,10 +94,10 @@
            Search the base object only.
          </adm:synopsis>
        </adm:value>
        <adm:value name="single-object">
        <adm:value name="single-level">
          <adm:synopsis>
            Search subordinate objects to the base object but not include
            the base object itself.
            Search immediate children of the base object but not include
            any of their descendants and the base object itself.
          </adm:synopsis>
        </adm:value>
        <adm:value name="subordinate-subtree">
opends/src/server/org/opends/server/backends/jeb/AttributeIndex.java
@@ -273,7 +273,7 @@
   * Close the attribute index.
   *
   * @throws DatabaseException if a JE database error occurs while
   * openning the index.
   * closing the index.
   */
  public void close() throws DatabaseException
  {
opends/src/server/org/opends/server/backends/jeb/ImportJob.java
@@ -1090,8 +1090,10 @@
        }
        // Remove any overlapping include branches.
        for(DN includeDN : includeBranches)
        Iterator<DN> includeBranchIterator = includeBranches.iterator();
        while(includeBranchIterator.hasNext())
        {
          DN includeDN = includeBranchIterator.next();
          boolean keep = true;
          for(DN dn : includeBranches)
          {
@@ -1103,15 +1105,17 @@
          }
          if(!keep)
          {
            includeBranches.remove(includeDN);
            includeBranchIterator.remove();
          }
        }
        // Remvoe any exclude branches that are not are not under a include
        // branch since they will be migrated as part of the existing entries
        // outside of the include branches anyways.
        for(DN excludeDN : excludeBranches)
        Iterator<DN> excludeBranchIterator = excludeBranches.iterator();
        while(excludeBranchIterator.hasNext())
        {
          DN excludeDN = excludeBranchIterator.next();
          boolean keep = false;
          for(DN includeDN : includeBranches)
          {
@@ -1123,7 +1127,7 @@
          }
          if(!keep)
          {
            excludeBranches.remove(excludeDN);
            excludeBranchIterator.remove();
          }
        }
opends/src/server/org/opends/server/backends/jeb/VLVIndex.java
@@ -254,6 +254,7 @@
    }
    this.count = new AtomicInteger(0);
    this.config.addChangeListener(this);
  }
  /**
@@ -286,6 +287,18 @@
  }
  /**
   * Close the VLV index.
   *
   * @throws DatabaseException if a JE database error occurs while
   * closing the index.
   */
  public void close() throws DatabaseException
  {
    super.close();
    this.config.removeChangeListener(this);
  }
  /**
   * Update the vlvIndex for a new entry.
   *
   * @param txn A database transaction, or null if none is required.
@@ -1431,6 +1444,9 @@
    if(adminActionRequired)
    {
      trusted = false;
      int msgID = MSGID_JEB_INDEX_ADD_REQUIRES_REBUILD;
      String message = getMessage(msgID, name);
      messages.add(message);
      try
      {
        state.putIndexTrustState(null, this, false);
opends/src/server/org/opends/server/messages/JebMessages.java
@@ -1603,12 +1603,13 @@
                    "index entry limit in index %s. This index must be " +
                    "rebuilt before it can use the new limit");
    registerMessage(MSGID_JEB_INDEX_ADD_REQUIRES_REBUILD,
                    "Index %s is currently operating in a degraded read-only " +
                    "state and must be rebuilt before it can used");
                    "Due to changes in the configuration, index %s is " +
                    "currently operating in a degraded state and must be " +
                    "rebuilt before it can used");
    registerMessage(MSGID_JEB_INDEX_CORRUPT_REQUIRES_REBUILD,
                    "An error occurred while reading from index %s. The " +
                    "index seems to be corrupt and is now operating in " +
                    "a degraded read-only state. The index must be rebuilt " +
                    "a degraded state. The index must be rebuilt " +
                    "before it can return to normal operation");
    registerMessage(MSGID_JEB_IMPORT_BACKEND_ONLINE,
                    "The backend must be disabled before the import process" +
opends/src/server/org/opends/server/tasks/ImportTask.java
@@ -224,19 +224,8 @@
    clearBackend = TaskUtils.getBoolean(attrList, false);
    // Make sure that either the "includeBranchStrings" argument or the
    // "backendID" argument was provided, but not both.
    if(!includeBranchStrings.isEmpty())
    {
      if(backendID != null)
      {
        int    msgID   = MSGID_LDIFIMPORT_CONFLICTING_OPTIONS;
        String message = getMessage(msgID, typeIncludeBranch.getNameOrOID(),
                                    typeBackendID.getNameOrOID());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    else if(backendID == null)
    // "backendID" argument was provided.
    if(includeBranchStrings.isEmpty() && backendID == null)
    {
      int    msgID   = MSGID_LDIFIMPORT_MISSING_BACKEND_ARGUMENT;
      String message = getMessage(msgID, typeIncludeBranch.getNameOrOID(),
@@ -245,15 +234,109 @@
                                   msgID);
    }
    Backend backend = null;
    ArrayList<DN> defaultIncludeBranches;
    ArrayList<DN> excludeBranches =
        new ArrayList<DN>(excludeBranchStrings.size());
    ArrayList<DN> includeBranches =
        new ArrayList<DN>(includeBranchStrings.size());
    for (String s : includeBranchStrings)
    {
      DN includeBranch;
      try
      {
        includeBranch = DN.decode(s);
      }
      catch (DirectoryException de)
      {
        int    msgID   = MSGID_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE;
        String message = getMessage(msgID, s, de.getErrorMessage());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
      catch (Exception e)
      {
        int    msgID   = MSGID_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE;
        String message = getMessage(msgID, s, getExceptionMessage(e));
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
      if(! includeBranches.contains(includeBranch))
      {
        includeBranches.add(includeBranch);
      }
    }
    for (String s : excludeBranchStrings)
    {
      DN excludeBranch;
      try
      {
        excludeBranch = DN.decode(s);
      }
      catch (DirectoryException de)
      {
        int    msgID   = MSGID_LDIFIMPORT_CANNOT_DECODE_EXCLUDE_BASE;
        String message = getMessage(msgID, s, de.getErrorMessage());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
      catch (Exception e)
      {
        int    msgID   = MSGID_LDIFIMPORT_CANNOT_DECODE_EXCLUDE_BASE;
        String message = getMessage(msgID, s, getExceptionMessage(e));
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
      if (! excludeBranches.contains(excludeBranch))
      {
        excludeBranches.add(excludeBranch);
      }
    }
    for (String filterString : excludeFilterStrings)
    {
      try
      {
        SearchFilter.createFilterFromString(filterString);
      }
      catch (DirectoryException de)
      {
        int    msgID   = MSGID_LDIFIMPORT_CANNOT_PARSE_EXCLUDE_FILTER;
        String message = getMessage(msgID, filterString,
                                    de.getErrorMessage());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    for (String filterString : includeFilterStrings)
    {
      try
      {
        SearchFilter.createFilterFromString(filterString);
      }
      catch (DirectoryException de)
      {
        int    msgID   = MSGID_LDIFIMPORT_CANNOT_PARSE_INCLUDE_FILTER;
        String message = getMessage(msgID, filterString,
                                    de.getErrorMessage());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
    if(backendID != null)
    {
      Backend backend = DirectoryServer.getBackend(backendID);
      backend = DirectoryServer.getBackend(backendID);
      if (backend == null)
      {
        int    msgID   = MSGID_LDIFIMPORT_NO_BACKENDS_FOR_ID;
        String message = getMessage(msgID, backendID);
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                   msgID);
                                     msgID);
      }
      else if (! backend.supportsLDIFImport())
      {
@@ -262,11 +345,12 @@
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
      // Make sure that if the "backendID" argument was provided and the
      // "append" option was not provided, the "clearBackend" argument was also
      // provided if there are more then one baseDNs for the backend being
      // imported.
      else if(!append && backend.getBaseDNs().length > 1 && !clearBackend)
      // Make sure that if the "backendID" argument was provided, no include
      // base was included, and the "append" ption was not provided, the
      // "clearBackend" argument was also provided if there are more then one
      // baseDNs for the backend being imported.
      else if(!append && includeBranchStrings.isEmpty() &&
          backend.getBaseDNs().length > 1 && !clearBackend)
      {
        StringBuilder builder = new StringBuilder();
        for(DN dn : backend.getBaseDNs())
@@ -284,31 +368,8 @@
    else
    {
      // Find the backend that includes all the branches.
      Backend backend = null;
      for (String s : includeBranchStrings)
      for(DN includeBranch : includeBranches)
      {
        DN includeBranch;
        try
        {
          includeBranch = DN.decode(s);
        }
        catch (DirectoryException de)
        {
          int    msgID   = MSGID_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE;
          String message = getMessage(msgID, s, de.getErrorMessage());
          logError(ErrorLogCategory.BACKEND, ErrorLogSeverity.SEVERE_ERROR,
                   message, msgID);
          throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                       msgID);
        }
        catch (Exception e)
        {
          int    msgID   = MSGID_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE;
          String message = getMessage(msgID, s, getExceptionMessage(e));
          throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                       msgID);
        }
        Backend locatedBackend = DirectoryServer.getBackend(includeBranch);
        if(locatedBackend != null)
        {
@@ -320,13 +381,35 @@
          {
            // The include branches span across multiple backends.
            int    msgID   = MSGID_LDIFIMPORT_INVALID_INCLUDE_BASE;
            String message = getMessage(msgID, s, backend.getBackendID());
            String message = getMessage(msgID,
                                        includeBranch.toNormalizedString(),
                                        backend.getBackendID());
            throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
                                         message, msgID);
          }
        }
      }
    }
    // Make sure the selected backend will handle all the include branches
    defaultIncludeBranches = new ArrayList<DN>(backend.getBaseDNs().length);
    for (DN dn : backend.getBaseDNs())
    {
      defaultIncludeBranches.add(dn);
    }
    for(DN includeBranch : includeBranches)
    {
      if (! Backend.handlesEntry(includeBranch, defaultIncludeBranches,
                                 excludeBranches))
      {
        int    msgID   = MSGID_LDIFIMPORT_INVALID_INCLUDE_BASE;
        String message = getMessage(msgID, includeBranch.toNormalizedString(),
                                    backend.getBackendID());
        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                     msgID);
      }
    }
  }
@@ -408,11 +491,11 @@
    // Get the backend into which the LDIF should be imported.
    Backend       backend = null;
    ArrayList<DN> defaultIncludeBranches;
    ArrayList<DN> excludeBranches = new ArrayList<DN>();
    ArrayList<DN> includeBranches = new ArrayList<DN>();
    ArrayList<DN> excludeBranches =
        new ArrayList<DN>(excludeBranchStrings.size());
    ArrayList<DN> includeBranches =
        new ArrayList<DN>(includeBranchStrings.size());
    includeBranches = new ArrayList<DN>(includeBranchStrings.size());
    for (String s : includeBranchStrings)
    {
      DN includeBranch;
@@ -437,7 +520,10 @@
        return TaskState.STOPPED_BY_ERROR;
      }
      includeBranches.add(includeBranch);
      if(! includeBranches.contains(includeBranch))
      {
        includeBranches.add(includeBranch);
      }
    }
    if(backendID != null)
@@ -460,11 +546,12 @@
                 message, msgID);
        return TaskState.STOPPED_BY_ERROR;
      }
      // Make sure that if the "backendID" argument was provided and the
      // "append" option was not provided, the "clearBackend" argument was also
      // provided if there are more then one baseDNs for the backend being
      // imported.
      else if(!append && backend.getBaseDNs().length > 1 && !clearBackend)
      // Make sure that if the "backendID" argument was provided, no include
      // base was included, and the "append" ption was not provided, the
      // "clearBackend" argument was also provided if there are more then one
      // baseDNs for the backend being imported.
      else if(!append && includeBranches.isEmpty() &&
          backend.getBaseDNs().length > 1 && !clearBackend)
      {
        StringBuilder builder = new StringBuilder();
        builder.append(backend.getBaseDNs()[0].toNormalizedString());
@@ -574,6 +661,23 @@
    {
      includeBranches = defaultIncludeBranches;
    }
    else
    {
      // Make sure the selected backend will handle all the include branches
      for(DN includeBranch : includeBranches)
      {
        if (! Backend.handlesEntry(includeBranch, defaultIncludeBranches,
                                   excludeBranches))
        {
          int    msgID   = MSGID_LDIFIMPORT_INVALID_INCLUDE_BASE;
          String message = getMessage(msgID, includeBranch.toNormalizedString(),
                                      backend.getBackendID());
          logError(ErrorLogCategory.BACKEND, ErrorLogSeverity.SEVERE_ERROR,
                   message, msgID);
          return TaskState.STOPPED_BY_ERROR;
        }
      }
    }
    // Create the LDIF import configuration to use when reading the LDIF.
    ArrayList<String> fileList = new ArrayList<String>(ldifFiles);
opends/src/server/org/opends/server/tools/ImportLDIF.java
@@ -420,20 +420,8 @@
    }
    // Make sure that either the "includeBranchStrings" argument or the
    // "backendID" argument was provided, but not both.
    if(includeBranchStrings.isPresent())
    {
      if(backendID.isPresent())
      {
        int    msgID   = MSGID_LDIFIMPORT_CONFLICTING_OPTIONS;
        String message = getMessage(msgID,
                                    includeBranchStrings.getLongIdentifier(),
                                    backendID.getLongIdentifier());
        err.println(wrapText(message, MAX_LINE_WIDTH));
        return 1;
      }
    }
    else if(! backendID.isPresent())
    // "backendID" argument was provided.
    if(!includeBranchStrings.isPresent() && !backendID.isPresent())
    {
      int    msgID   = MSGID_LDIFIMPORT_MISSING_BACKEND_ARGUMENT;
      String message = getMessage(msgID,
@@ -925,12 +913,13 @@
      }
    }
    // Make sure that if the "backendID" argument was provided and the "append"
    // option was not provided, the "clearBackend" argument was also
    // provided if there are more then one baseDNs for the backend being
    // imported.
    if(backendID.isPresent() && !append.isPresent() &&
        defaultIncludeBranches.size() > 1 && !clearBackend.isPresent())
    // Make sure that if the "backendID" argument was provided, no include base
    // was included, and the "append" ption was not provided, the "clearBackend"
    // argument was also provided if there are more then one baseDNs for the
    // backend being imported.
    if(backendID.isPresent() && !includeBranchStrings.isPresent() &&
        !append.isPresent() && defaultIncludeBranches.size() > 1 &&
        !clearBackend.isPresent())
    {
      StringBuilder builder = new StringBuilder();
      builder.append(backend.getBaseDNs()[0].toNormalizedString());
opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestImportJob.java
@@ -71,6 +71,11 @@
      "objectclass: organizationalUnit\n" +
      "ou: People\n" +
      "\n" +
      "dn: ou=Others,ou=People,dc=importtest,dc=com\n" +
      "objectclass: top\n" +
      "objectclass: organizationalUnit\n" +
      "ou: Others\n" +
      "\n" +
      "dn: dc=importtest1,dc=com\n" +
      "objectclass: top\n" +
      "objectclass: domain\n" +
@@ -326,9 +331,10 @@
        if(baseDN.toString().equals("dc=importtest,dc=com"))
        {
          assertEquals(entryContainer.getEntryCount(), 4);
          assertEquals(entryContainer.getEntryCount(), 5);
          assertTrue(entryContainer.entryExists(baseDN));
          assertTrue(entryContainer.entryExists(DN.decode("ou=People,dc=importtest,dc=com")));
          assertTrue(entryContainer.entryExists(DN.decode("ou=Others,ou=People,dc=importtest,dc=com")));
          assertTrue(entryContainer.entryExists(DN.decode("uid=user.0,ou=People,dc=importtest,dc=com")));
          assertTrue(entryContainer.entryExists(DN.decode("uid=user.539,ou=People,dc=importtest,dc=com")));
@@ -365,6 +371,94 @@
  }
  @Test(dependsOnMethods = "testImportAll")
  public void testImportPartial() throws Exception
  {
    ArrayList<String> fileList = new ArrayList<String>();
    fileList.add(homeDirName + File.separator + "top.ldif");
    fileList.add(homeDirName + File.separator + "entries1.ldif");
    ArrayList<DN> includeBranches = new ArrayList<DN>();
    includeBranches.add(DN.decode("ou=People,dc=importtest,dc=com"));
    ArrayList<DN> excludeBranches = new ArrayList<DN>();
    excludeBranches.add(DN.decode("ou=Others,ou=People,dc=importtest,dc=com"));
    ByteArrayOutputStream rejectedEntries = new ByteArrayOutputStream();
    ByteArrayOutputStream skippedEntries = new ByteArrayOutputStream();
    LDIFImportConfig importConfig = new LDIFImportConfig(fileList);
    importConfig.setAppendToExistingData(false);
    importConfig.setReplaceExistingEntries(false);
    importConfig.setValidateSchema(true);
    importConfig.writeRejectedEntries(rejectedEntries);
    importConfig.writeSkippedEntries(skippedEntries);
    importConfig.setIncludeBranches(includeBranches);
    importConfig.setExcludeBranches(excludeBranches);
    be=(BackendImpl) DirectoryServer.getBackend(beID);
    TaskUtils.disableBackend(beID);
    try
    {
      be.importLDIF(importConfig);
    }
    finally
    {
      TaskUtils.enableBackend(beID);
    }
    be=(BackendImpl) DirectoryServer.getBackend(beID);
    RootContainer rootContainer = be.getRootContainer();
    EntryContainer entryContainer;
    assertTrue(rejectedEntries.size() <= 0);
    for(DN baseDN : baseDNs)
    {
      entryContainer = rootContainer.getEntryContainer(baseDN);
      entryContainer.sharedLock.lock();
      try
      {
        assertNotNull(entryContainer);
        if(baseDN.toString().equals("dc=importtest,dc=com"))
        {
          assertEquals(entryContainer.getEntryCount(), 5);
          assertTrue(entryContainer.entryExists(baseDN));
          assertTrue(entryContainer.entryExists(DN.decode("ou=People,dc=importtest,dc=com")));
          assertTrue(entryContainer.entryExists(DN.decode("ou=Others,ou=People,dc=importtest,dc=com")));
          assertTrue(entryContainer.entryExists(DN.decode("uid=user.0,ou=People,dc=importtest,dc=com")));
          assertTrue(entryContainer.entryExists(DN.decode("uid=user.539,ou=People,dc=importtest,dc=com")));
          VerifyConfig verifyConfig = new VerifyConfig();
          verifyConfig.setBaseDN(baseDN);
          Entry statEntry=bldStatEntry("");
          be=(BackendImpl) DirectoryServer.getBackend(beID);
          be.verifyBackend(verifyConfig, statEntry);
          assertEquals(getStatEntryCount(statEntry, errorCount), 0);
        }
        else if(baseDN.toString().equals("dc=importtest1,dc=com"))
        {
          assertEquals(entryContainer.getEntryCount(), 3);
          assertTrue(entryContainer.entryExists(baseDN));
          assertTrue(entryContainer.entryExists(DN.decode("uid=user.446,dc=importtest1,dc=com")));
          assertTrue(entryContainer.entryExists(DN.decode("uid=user.362,dc=importtest1,dc=com")));
          VerifyConfig verifyConfig = new VerifyConfig();
          verifyConfig.setBaseDN(baseDN);
          Entry statEntry=bldStatEntry("");
          be=(BackendImpl) DirectoryServer.getBackend(beID);
          be.verifyBackend(verifyConfig, statEntry);
          assertEquals(getStatEntryCount(statEntry, errorCount), 0);
        }
      }
      finally
      {
        entryContainer.sharedLock.unlock();
      }
    }
  }
  @Test(dependsOnMethods = "testImportPartial")
  public void testImportReplaceExisting() throws Exception
  {
    ByteArrayOutputStream rejectedEntries = new ByteArrayOutputStream();
@@ -488,7 +582,7 @@
      {
        if(baseDN.toString().equals("dc=importtest,dc=com"))
        {
          assertEquals(entryContainer.getEntryCount(), 4);
          assertEquals(entryContainer.getEntryCount(), 5);
          assertTrue(entryContainer.entryExists(baseDN));
          assertTrue(entryContainer.entryExists(DN.decode("ou=People,dc=importtest,dc=com")));
          assertTrue(entryContainer.entryExists(DN.decode("uid=user.0,ou=People,dc=importtest,dc=com")));
@@ -510,7 +604,7 @@
    }
  }
  @Test(dependsOnMethods = "testImportAll")
  @Test(dependsOnMethods = "testImportPartial")
  public void testImportNotReplaceExisting() throws Exception
  {
    ByteArrayOutputStream rejectedEntries = new ByteArrayOutputStream();
@@ -534,7 +628,7 @@
    assertTrue(rejectedEntries.toString().contains("uid=user.446,dc=importtest1,dc=com"));
  }
  @Test(dependsOnMethods = "testImportAll")
  @Test(dependsOnMethods = "testImportPartial")
  public void testImportSkip() throws Exception
  {
    ArrayList<DN> excludeBranches = new ArrayList<DN>();
opends/tests/unit-tests-testng/src/server/org/opends/server/tasks/TestImportAndExport.java
@@ -32,10 +32,13 @@
import org.testng.annotations.AfterClass;
import org.testng.annotations.DataProvider;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.AddOperation;
import org.opends.server.TestCaseUtils;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.api.TestTaskListener;
import org.opends.server.types.Entry;
import org.opends.server.types.ObjectClass;
import org.opends.server.types.ResultCode;
import org.opends.server.backends.task.TaskState;
import static org.testng.Assert.*;
@@ -136,7 +139,7 @@
  public Object[][] createData() throws Exception
  {
    return new Object[][] {
         // A fairly simple, valid import task.
         // A fairly simple, valid import task using backend ID.
         {
              TestCaseUtils.makeEntry(
                   "dn: ds-task-id=" + UUID.randomUUID() +
@@ -155,6 +158,25 @@
              ),
              TaskState.COMPLETED_SUCCESSFULLY
         },
         // A fairly simple, valid import task using include base DN.
         {
              TestCaseUtils.makeEntry(
                   "dn: ds-task-id=" + UUID.randomUUID() +
                        ",cn=Scheduled Tasks,cn=Tasks",
                   "objectclass: top",
                   "objectclass: ds-task",
                   "objectclass: ds-task-import",
                   "ds-task-class-name: org.opends.server.tasks.ImportTask",
                   "ds-task-import-include-branch: dc=example,dc=com",
                   "ds-task-import-ldif-file: " + ldifFile.getPath(),
                   "ds-task-import-reject-file: " + rejectFile.getPath(),
                   "ds-task-import-overwrite-rejects: TRUE",
                   "ds-task-import-exclude-attribute: description",
                   "ds-task-import-exclude-filter: (st=CA)",
                   "ds-task-import-exclude-branch: o=exclude,dc=example,dc=com"
              ),
              TaskState.COMPLETED_SUCCESSFULLY
         },
         // A complex, valid import task.
         {
              TestCaseUtils.makeEntry(
@@ -182,7 +204,7 @@
              ),
              TaskState.COMPLETED_SUCCESSFULLY
         },
         // LDIF file does not exist.
         // A partial, valid import task.
         {
              TestCaseUtils.makeEntry(
                   "dn: ds-task-id=" + UUID.randomUUID() +
@@ -191,40 +213,15 @@
                   "objectclass: ds-task",
                   "objectclass: ds-task-import",
                   "ds-task-class-name: org.opends.server.tasks.ImportTask",
                   "ds-task-import-ldif-file: doesnotexist",
                   "ds-task-import-backend-id: userRoot"
              ),
              TaskState.STOPPED_BY_ERROR
         },
         // Invalid exclude filter.
         {
              TestCaseUtils.makeEntry(
                   "dn: ds-task-id=" + UUID.randomUUID() +
                        ",cn=Scheduled Tasks,cn=Tasks",
                   "objectclass: top",
                   "objectclass: ds-task",
                   "objectclass: ds-task-import",
                   "ds-task-class-name: org.opends.server.tasks.ImportTask",
                   "ds-task-import-include-branch: ou=people,dc=example,dc=com",
                   "ds-task-import-ldif-file: " + ldifFile.getPath(),
                   "ds-task-import-backend-id: userRoot",
                   "ds-task-import-exclude-filter: ()"
                   "ds-task-import-reject-file: " + rejectFile.getPath(),
                   "ds-task-import-overwrite-rejects: TRUE",
                   "ds-task-import-exclude-attribute: description",
                   "ds-task-import-exclude-filter: (st=CA)",
                   "ds-task-import-exclude-branch: o=exclude,dc=example,dc=com"
              ),
              TaskState.STOPPED_BY_ERROR
         },
         // Invalid include filter.
         {
              TestCaseUtils.makeEntry(
                   "dn: ds-task-id=" + UUID.randomUUID() +
                        ",cn=Scheduled Tasks,cn=Tasks",
                   "objectclass: top",
                   "objectclass: ds-task",
                   "objectclass: ds-task-import",
                   "ds-task-class-name: org.opends.server.tasks.ImportTask",
                   "ds-task-import-ldif-file: " + ldifFile.getPath(),
                   "ds-task-import-backend-id: userRoot",
                   "ds-task-import-include-filter: ()"
              ),
              TaskState.STOPPED_BY_ERROR
              TaskState.COMPLETED_SUCCESSFULLY
         },
         // Backend id does not exist.
         {
@@ -235,37 +232,8 @@
                   "objectclass: ds-task",
                   "objectclass: ds-task-import",
                   "ds-task-class-name: org.opends.server.tasks.ImportTask",
                   "ds-task-import-ldif-file: " + ldifFile.getPath(),
                   "ds-task-import-backend-id: doesnotexist"
              ),
              TaskState.STOPPED_BY_ERROR
         },
         // Backend does not support import.
         {
              TestCaseUtils.makeEntry(
                   "dn: ds-task-id=" + UUID.randomUUID() +
                        ",cn=Scheduled Tasks,cn=Tasks",
                   "objectclass: top",
                   "objectclass: ds-task",
                   "objectclass: ds-task-import",
                   "ds-task-class-name: org.opends.server.tasks.ImportTask",
                   "ds-task-import-ldif-file: " + ldifFile.getPath(),
                   "ds-task-import-backend-id: monitor"
              ),
              TaskState.STOPPED_BY_ERROR
         },
         // Backend does not handle include branch.
         {
              TestCaseUtils.makeEntry(
                   "dn: ds-task-id=" + UUID.randomUUID() +
                        ",cn=Scheduled Tasks,cn=Tasks",
                   "objectclass: top",
                   "objectclass: ds-task",
                   "objectclass: ds-task-import",
                   "ds-task-class-name: org.opends.server.tasks.ImportTask",
                   "ds-task-import-ldif-file: " + ldifFile.getPath(),
                   "ds-task-import-backend-id: userRoot",
                   "ds-task-import-include-branch: dc=opends,dc=org"
                   "ds-task-import-ldif-file: doesnotexist",
                   "ds-task-import-backend-id: userRoot"
              ),
              TaskState.STOPPED_BY_ERROR
         },
@@ -289,12 +257,111 @@
  }
  /**
   * Import and export tasks bad test data provider.
   *
   * @return The array of tasks test data.  The first column is a task entry
   *  and the second column is the expected completed task state.
   */
  @DataProvider(name = "badimportexport")
  public Object[][] createBadData() throws Exception
  {
    return new Object[][] {
        // Invalid exclude filter.
        {
            TestCaseUtils.makeEntry(
                "dn: ds-task-id=" + UUID.randomUUID() +
                    ",cn=Scheduled Tasks,cn=Tasks",
                "objectclass: top",
                "objectclass: ds-task",
                "objectclass: ds-task-import",
                "ds-task-class-name: org.opends.server.tasks.ImportTask",
                "ds-task-import-ldif-file: " + ldifFile.getPath(),
                "ds-task-import-backend-id: userRoot",
                "ds-task-import-exclude-filter: ()"
            ),
            ResultCode.UNWILLING_TO_PERFORM
        },
        // Invalid include filter.
        {
            TestCaseUtils.makeEntry(
                "dn: ds-task-id=" + UUID.randomUUID() +
                    ",cn=Scheduled Tasks,cn=Tasks",
                "objectclass: top",
                "objectclass: ds-task",
                "objectclass: ds-task-import",
                "ds-task-class-name: org.opends.server.tasks.ImportTask",
                "ds-task-import-ldif-file: " + ldifFile.getPath(),
                "ds-task-import-backend-id: userRoot",
                "ds-task-import-include-filter: ()"
            ),
            ResultCode.UNWILLING_TO_PERFORM
        },
        // Backend id does not exist.
        {
            TestCaseUtils.makeEntry(
                "dn: ds-task-id=" + UUID.randomUUID() +
                    ",cn=Scheduled Tasks,cn=Tasks",
                "objectclass: top",
                "objectclass: ds-task",
                "objectclass: ds-task-import",
                "ds-task-class-name: org.opends.server.tasks.ImportTask",
                "ds-task-import-ldif-file: " + ldifFile.getPath(),
                "ds-task-import-backend-id: doesnotexist"
            ),
            ResultCode.UNWILLING_TO_PERFORM
        },
        // Backend does not support import.
        {
            TestCaseUtils.makeEntry(
                "dn: ds-task-id=" + UUID.randomUUID() +
                    ",cn=Scheduled Tasks,cn=Tasks",
                "objectclass: top",
                "objectclass: ds-task",
                "objectclass: ds-task-import",
                "ds-task-class-name: org.opends.server.tasks.ImportTask",
                "ds-task-import-ldif-file: " + ldifFile.getPath(),
                "ds-task-import-backend-id: monitor"
            ),
            ResultCode.UNWILLING_TO_PERFORM
        },
        // Backend does not handle include branch.
        {
            TestCaseUtils.makeEntry(
                "dn: ds-task-id=" + UUID.randomUUID() +
                    ",cn=Scheduled Tasks,cn=Tasks",
                "objectclass: top",
                "objectclass: ds-task",
                "objectclass: ds-task-import",
                "ds-task-class-name: org.opends.server.tasks.ImportTask",
                "ds-task-import-ldif-file: " + ldifFile.getPath(),
                "ds-task-import-backend-id: userRoot",
                "ds-task-import-include-branch: dc=opends,dc=org"
            ),
            ResultCode.UNWILLING_TO_PERFORM
        },
        // Not specifying a destination.
        {
            TestCaseUtils.makeEntry(
                "dn: ds-task-id=" + UUID.randomUUID() +
                    ",cn=Scheduled Tasks,cn=Tasks",
                "objectclass: top",
                "objectclass: ds-task",
                "objectclass: ds-task-import",
                "ds-task-class-name: org.opends.server.tasks.ImportTask",
                "ds-task-import-ldif-file: " + ldifFile.getPath()
            ),
            ResultCode.UNWILLING_TO_PERFORM
        }
    };
  }
  /**
   * Test that various import and export task definitions complete with the
   * expected state.
   * @param taskEntry The task entry.
   * @param expectedState The expected completion state of the task.
   */
  @Test(enabled = false, dataProvider = "importexport", groups = "slow")
  @Test(dataProvider = "importexport", groups = "slow")
  public void testImportExport(Entry taskEntry, TaskState expectedState)
       throws Exception
  {
@@ -329,4 +396,26 @@
    }
 }
  /**
   * Add a task definition and check that it completes with the expected state.
   * @param taskEntry The task entry.
   * @param resultCode The expected result code of the task add.
   * @throws Exception If the test fails.
   */
  @Test(dataProvider = "badimportexport")
  public void testBadTask(Entry taskEntry, ResultCode resultCode)
      throws Exception
  {
    InternalClientConnection connection =
        InternalClientConnection.getRootConnection();
    // Add the task.
    AddOperation addOperation =
        connection.processAdd(taskEntry.getDN(),
                              taskEntry.getObjectClasses(),
                              taskEntry.getUserAttributes(),
                              taskEntry.getOperationalAttributes());
    assertEquals(addOperation.getResultCode(), resultCode);
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/tools/ImportLDIFTestCase.java
@@ -51,6 +51,7 @@
  String configFilePath ;
  private String homeDirName;
  private String beID;
  private String baseDN = "dc=example,dc=com";
  /**
  * Ensures that the ldif file is created with the entry.
@@ -196,6 +197,41 @@
    assertEntry(attr,true);
  }
  /**
   * Tests a simple Import LDIF using base DN with none of the attributes
   * excluded or included. It is expected to import the entry(ies)
   * with all the attributes in the ldif file.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test
  public void testImportDefaultBaseDN() throws Exception
  {
    File reject = File.createTempFile("reject", ".ldif");
    String rejectFilePath = reject.getAbsolutePath();
    String[] args =
    {
      "-f", DirectoryServer.getConfigFile(),
      "-l", ldifFilePath,
      "-b", baseDN,
      "-R", rejectFilePath
    };
    assertEquals(ImportLDIF.mainImportLDIF(args,false,System.out,System.err),0);
    //Reject file should be empty.
    assertRejectedFile(reject,true);
    //check the presence of some random attributes.
    Attribute[]  attr =
    {
      new Attribute ("description",
          "This is the description for Aaccf Amar"),
      new Attribute("mail","user.0@example.com"),
      new Attribute ("creatorsname", "cn=Import") ,
      new Attribute("modifiersname","cn=Import")
    }    ;
    assertEntry(attr,true);
  }
  /**