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

Jean-Noël Rouvignac
22.03.2015 d7ff20abfb73f67c24d70cd27d6c6f5124503aa0
EntryContainer.java:
Remove null checks on operation objects

PluggableBackendImplTestCase.java:
Added asserts, improved the tests

fixup
4 files modified
236 ■■■■■ changed files
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java 72 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/TestCaseUtils.java 75 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/ControlsTestCase.java 8 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/PluggableBackendImplTestCase.java 81 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java
@@ -1529,12 +1529,9 @@
            dn2uri.addEntry(txn, entry);
            id2childrenCount.updateTotalCount(txn, 1);
            indexBuffer.flush(txn);
            if (addOperation != null)
            {
              // One last check before committing
              addOperation.checkIfCanceled(true);
            }
          }
          catch (StorageRuntimeException | DirectoryException | CanceledOperationException e)
          {
            throw e;
@@ -1648,8 +1645,7 @@
            }
            // Delete the subordinate entries in dn2id if requested.
            final boolean isSubtreeDelete = deleteOperation != null
                    && deleteOperation.getRequestControl(SubtreeDeleteControl.DECODER) != null;
            final boolean isSubtreeDelete = deleteOperation.getRequestControl(SubtreeDeleteControl.DECODER) != null;
            /* draft-armijo-ldap-treedelete, 4.1 Tree Delete Semantics: The server MUST NOT chase referrals stored in
             * the tree. If information about referrals is stored in this section of the tree, this pointer will be
@@ -1685,7 +1681,7 @@
                }
                entriesToBeDeleted.add(cursor.getValue().longValue());
                cursor.delete();
                checkIfCanceled(false);
                deleteOperation.checkIfCanceled(false);
              }
            }
            // The target entry will have the lowest entryID so it will remain the first element.
@@ -1723,12 +1719,12 @@
                  entryCache.removeEntry(entry.getName());
                }
                isBaseEntry = false;
                checkIfCanceled(false);
                deleteOperation.checkIfCanceled(false);
              }
            }
            id2childrenCount.updateTotalCount(txn, -entriesToBeDeleted.size());
            indexBuffer.flush(txn);
            checkIfCanceled(true);
            deleteOperation.checkIfCanceled(true);
            if (isSubtreeDelete)
            {
              deleteOperation.addAdditionalLogItem(unquotedKeyValue(getClass(), "deletedEntries",
@@ -1753,7 +1749,7 @@
        private void invokeSubordinateDeletePlugins(final Entry entry) throws DirectoryException
        {
          if (deleteOperation != null && !deleteOperation.isSynchronizationOperation())
          if (!deleteOperation.isSynchronizationOperation())
          {
            SubordinateDelete pluginResult =
                    getPluginConfigManager().invokeSubordinateDeletePlugins(deleteOperation, entry);
@@ -1764,14 +1760,6 @@
            }
          }
        }
        private void checkIfCanceled(boolean signalTooLate) throws CanceledOperationException
        {
          if (deleteOperation != null)
          {
            deleteOperation.checkIfCanceled(signalTooLate);
          }
        }
      });
    }
    catch (Exception e)
@@ -1938,39 +1926,14 @@
            // Ensure same ordering as deleteEntry: id2entry, dn2uri, then indexes.
            id2entry.put(txn, entryID, encodedNewEntry);
            // Update the referral tree.
            if (modifyOperation != null)
            {
              // In this case we know from the operation what the modifications were.
              List<Modification> mods = modifyOperation.getModifications();
              dn2uri.modifyEntry(txn, oldEntry, newEntry, mods);
            }
            else
            {
              dn2uri.replaceEntry(txn, oldEntry, newEntry);
            }
            // Update the indexes.
            if (modifyOperation != null)
            {
              // In this case we know from the operation what the modifications were.
              List<Modification> mods = modifyOperation.getModifications();
              indexModifications(indexBuffer, oldEntry, newEntry, entryID, mods);
            }
            else
            {
              // The most optimal would be to figure out what the modifications were.
              removeEntryFromIndexes(indexBuffer, oldEntry, entryID);
              insertEntryIntoIndexes(indexBuffer, newEntry, entryID);
            }
            // Update the referral tree and indexes
            dn2uri.modifyEntry(txn, oldEntry, newEntry, modifyOperation.getModifications());
            indexModifications(indexBuffer, oldEntry, newEntry, entryID, modifyOperation.getModifications());
            indexBuffer.flush(txn);
            if(modifyOperation != null)
            {
              // One last check before committing
              modifyOperation.checkIfCanceled(true);
            }
            // Update the entry cache.
            EntryCache<?> entryCache = DirectoryServer.getEntryCache();
@@ -2105,12 +2068,12 @@
              {
                renameSingleEntry(txn, renamedEntryID, cursor, indexBuffer, newTargetDN, renumberEntryIDs, isBaseEntry);
                isBaseEntry = false;
                checkIfCanceled(false);
                modifyDNOperation.checkIfCanceled(false);
              }
            }
            indexBuffer.flush(txn);
            checkIfCanceled(true);
            modifyDNOperation.checkIfCanceled(true);
          }
          catch (StorageRuntimeException | DirectoryException | CanceledOperationException e)
          {
@@ -2155,7 +2118,7 @@
              dn2uri.checkTargetForReferral(oldEntry, null);
            }
            newEntry = newTargetEntry;
            modifications = modifyDNOperation != null ? modifyDNOperation.getModifications() : null;
            modifications = modifyDNOperation.getModifications();
          }
          else
          {
@@ -2198,14 +2161,6 @@
          }
        }
        private void checkIfCanceled(boolean signalTooLate) throws CanceledOperationException
        {
          if (modifyDNOperation != null)
          {
            modifyDNOperation.checkIfCanceled(signalTooLate);
          }
        }
        private List<Modification> invokeSubordinateModifyDNPlugins(
                final Entry oldEntry, final Entry newEntry) throws DirectoryException
        {
@@ -2218,7 +2173,7 @@
          //          provide an unmodifiable list for the modifications element.
          // FIXME -- This will need to be updated appropriately if we decided that
          //          these plugins should be invoked for synchronization operations.
          if (modifyDNOperation != null && !modifyDNOperation.isSynchronizationOperation())
          if (!modifyDNOperation.isSynchronizationOperation())
          {
            SubordinateModifyDN pluginResult = getPluginConfigManager().invokeSubordinateModifyDNPlugins(
                    modifyDNOperation, oldEntry, newEntry, modifications);
@@ -2397,8 +2352,6 @@
   */
  private static boolean isManageDsaITOperation(Operation operation)
  {
    if(operation != null)
    {
      List<Control> controls = operation.getRequestControls();
      if (controls != null)
      {
@@ -2410,7 +2363,6 @@
          }
        }
      }
    }
    return false;
  }
opendj-server-legacy/src/test/java/org/opends/server/TestCaseUtils.java
@@ -80,6 +80,7 @@
import com.forgerock.opendj.util.OperatingSystem;
import static org.mockito.Mockito.*;
import static org.opends.server.loggers.TextAccessLogPublisher.*;
import static org.opends.server.loggers.TextErrorLogPublisher.*;
import static org.opends.server.loggers.TextHTTPAccessLogPublisher.*;
@@ -88,9 +89,7 @@
import static org.opends.server.util.StaticUtils.*;
import static org.testng.Assert.*;
/**
 * This class defines some utility functions which can be used by test cases.
 */
/** This class defines some utility functions which can be used by test cases. */
@SuppressWarnings("javadoc")
public final class TestCaseUtils {
  /** The name of the system property that specifies the server build root. */
@@ -345,7 +344,6 @@
        copyDirectory(new File(installedRoot), testInstallRoot);
        // Get the instance location
      }
      else
      {
@@ -615,10 +613,7 @@
    waitForOpsToComplete();
  }
  /**
   * This can be made public if quiesceServer becomes too heavy-weight in
   * some circumstance.
   */
  /** This can be made public if quiesceServer becomes too heavy-weight in some circumstance. */
  private static void waitForOpsToComplete()
  {
    try {
@@ -630,7 +625,6 @@
    }
  }
  /**
   * Binds to the given socket port on the local host.
   * @return the bounded Server socket.
@@ -727,8 +721,6 @@
    DirectoryServer.setSchema(schemaBeforeStartingFakeServer);
  }
  /**
   * Shut down the server. This should only be called at the end of the test
   * suite and not by any unit tests.
@@ -815,9 +807,7 @@
    }
  }
  /**
   * Clears a memory-based backend.
   */
  /** Clears a memory-based backend. */
  public static void clearMemoryBackend(String backendID) throws Exception
  {
    MemoryBackend memoryBackend = (MemoryBackend) DirectoryServer.getBackend(backendID);
@@ -852,7 +842,7 @@
    if (clearBackend(b) && baseDN != null)
    {
      Entry e = createEntry(DN.valueOf(baseDN));
      DirectoryServer.getBackend(backendId).addEntry(e, null);
      DirectoryServer.getBackend(backendId).addEntry(e, mock(AddOperation.class));
    }
  }
@@ -860,7 +850,7 @@
  {
    if (b instanceof BackendImpl)
    {
      final BackendImpl backend = (BackendImpl) b;
      final BackendImpl<?> backend = (BackendImpl<?>) b;
      final RootContainer rootContainer = backend.getRootContainer();
      if (rootContainer != null)
      {
@@ -987,7 +977,6 @@
    }
  }
  /**
   * Get the LDAP port the test environment Directory Server instance is
   * running on.
@@ -1069,14 +1058,12 @@
    // No implementation.
  }
  ////////////////////////////////////////////////////////////////////////////
  ////////////////////////////////////////////////////////////////////////////
  // Various methods for converting LDIF Strings to Entries
  ////////////////////////////////////////////////////////////////////////////
  ////////////////////////////////////////////////////////////////////////////
  /**
   * Returns a modifiable List of entries parsed from the provided LDIF.
   * It's best to call this after the server has been initialized so
@@ -1202,8 +1189,6 @@
     return entriesFromLdifString(makeLdif(lines));
  }
  /**
   * Adds the provided entry to the Directory Server using an internal
   * operation.
@@ -1218,8 +1203,6 @@
    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
  }
  /**
   * Deletes the provided entry from the Directory Server using an
   * internal operation.
@@ -1247,12 +1230,10 @@
    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
  }
  public static boolean canBind(String dn, String pw) throws Exception
  {
    // Check that the user can bind.
    try (Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());)
    try (Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort()))
    {
      TestCaseUtils.configureSocket(s);
      ASN1Reader r = ASN1.getReader(s.getInputStream());
@@ -1275,8 +1256,6 @@
    }
  }
  /**
   * Configures a socket for use in unit tests. This should only be used if the
   * socket is not expected to timeout.
@@ -1291,8 +1270,6 @@
    s.setSoTimeout(60 * 1000);
  }
  /**
   * Adds the provided entry to the Directory Server using an internal
   * operation.
@@ -1312,8 +1289,6 @@
    return e;
  }
  /**
   * Adds the provided entry to the Directory Server using an internal
   * operation.
@@ -1331,8 +1306,6 @@
    return addOperation.getResultCode();
  }
  /**
   * Adds the provided set of entries to the Directory Server using internal
   * operations.
@@ -1349,8 +1322,6 @@
    }
  }
  /**
   * Adds the provided set of entries to the Directory Server using internal
   * operations.
@@ -1369,8 +1340,6 @@
    }
  }
  /**
   * Applies a set of modifications to the server as described in the provided
   * set of lines (using LDIF change form).  The changes will be applied over
@@ -1455,9 +1424,7 @@
    }
  }
  /**
   * Return a Map constructed via alternating key and value pairs.
   */
  /** Return a Map constructed via alternating key and value pairs. */
  public static Map<String, String> makeMap(String... keyValuePairs)
  {
    Map<String, String> map = new LinkedHashMap<>();
@@ -1482,12 +1449,10 @@
   *  must write something to System.out. */
  public static final PrintStream originalSystemOut = System.out;
  /** System.err is redirected to here so that we can only print it out
   *  if a test fails. */
  /** System.err is redirected to here so that we can only print it out if a test fails. */
  private static final ByteArrayOutputStream redirectedSystemErr = new ByteArrayOutputStream();
  /** System.out is redirected to here so that we can only print it out
   *  if a test fails. */
  /** System.out is redirected to here so that we can only print it out if a test fails. */
  private static final ByteArrayOutputStream redirectedSystemOut = new ByteArrayOutputStream();
  public static synchronized void suppressOutput() {
@@ -1552,9 +1517,7 @@
    redirectedSystemErr.reset();
  }
  /**
   * Clear everything written to the Access, Error, or Debug loggers.
   */
  /** Clear everything written to the Access, Error, or Debug loggers. */
  public static synchronized void clearLoggersContents() {
    ACCESS_TEXT_WRITER.clear();
    ERROR_TEXT_WRITER.clear();
@@ -1642,7 +1605,6 @@
    return lines;
  }
  /** Read the contents of a file and return it as a String. */
  private static byte[] readFileBytes(File file) throws IOException {
    FileInputStream fis = new FileInputStream(file);
@@ -1675,7 +1637,6 @@
    return bytes;
  }
  /** Store the contents of a String in a file. */
  public static void writeFile(File file, String contents) throws IOException {
    writeFile(file.getAbsolutePath(), contents);
@@ -1736,8 +1697,6 @@
    assertEquals(DSConfig.main(fullArgs, System.out, System.err), 0);
  }
  /**
   * Gets the root configuration associated with the active server
   * instance. This root configuration can then be used to access and
@@ -1766,8 +1725,6 @@
    return context.getRootConfiguration();
  }
  /**
   * Return a String representation of all of the current threads.
   * @return a dump of all Threads on the server
@@ -1776,7 +1733,6 @@
  {
    Map<Thread,StackTraceElement[]> threadStacks = Thread.getAllStackTraces();
    // Re-arrange all of the elements by thread ID so that there is some logical order.
    Map<Long, Map.Entry<Thread, StackTraceElement[]>> orderedStacks = new TreeMap<>();
    for (Map.Entry<Thread,StackTraceElement[]> e : threadStacks.entrySet())
@@ -1900,18 +1856,15 @@
  /** FIXME Replace with {@link Assert#assertNotEquals(Object, Object, String)} once we upgrade to testng >= 6.1. */
  public static void assertNotEquals(Object actual1, Object actual2, String message)
  {
    boolean fail = false;
    try
    {
      Assert.assertEquals(actual1, actual2);
      fail = true;
      Assert.fail(message);
    }
    catch (AssertionError e)
    {
    }
    if (fail)
    {
      Assert.fail(message);
      // this is good: they are not equals
      return;
    }
  }
}
opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/ControlsTestCase.java
@@ -26,7 +26,7 @@
package org.opends.server.backends.pluggable;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.*;
import static org.opends.server.ConfigurationMock.legacyMockCfg;
import static org.opends.server.TestCaseUtils.makeEntry;
import static org.opends.server.protocols.internal.InternalClientConnection.getRootConnection;
@@ -55,6 +55,7 @@
import org.opends.server.controls.ServerSideSortResponseControl;
import org.opends.server.controls.VLVRequestControl;
import org.opends.server.controls.VLVResponseControl;
import org.opends.server.core.AddOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.protocols.internal.SearchRequest;
@@ -154,10 +155,11 @@
    backend.configureBackend(backendCfg, DirectoryServer.getInstance().getServerContext());
    backend.openBackend();
    backend.addEntry(makeEntry("dn: " + BACKEND_BASE_DN, "objectclass: top", "objectclass: domain"), null);
    AddOperation op = mock(AddOperation.class);
    backend.addEntry(makeEntry("dn: " + BACKEND_BASE_DN, "objectclass: top", "objectclass: domain"), op);
    for (final User user : USERS)
    {
      backend.addEntry(user.toEntry(), null);
      backend.addEntry(user.toEntry(), op);
    }
  }
opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/PluggableBackendImplTestCase.java
@@ -26,9 +26,8 @@
package org.opends.server.backends.pluggable;
import static org.assertj.core.api.Assertions.assertThat;
import static org.forgerock.opendj.ldap.ModificationType.ADD;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.forgerock.opendj.ldap.ModificationType.*;
import static org.mockito.Mockito.*;
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;
@@ -38,6 +37,7 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
@@ -51,6 +51,8 @@
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.SearchScope;
import org.forgerock.util.Reject;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.opends.server.DirectoryServerTestCase;
import org.opends.server.TestCaseUtils;
import org.opends.server.admin.std.meta.BackendIndexCfgDefn.IndexType;
@@ -61,8 +63,8 @@
import org.opends.server.api.Backend.BackendOperation;
import org.opends.server.api.ClientConnection;
import org.opends.server.backends.RebuildConfig;
import org.opends.server.backends.VerifyConfig;
import org.opends.server.backends.RebuildConfig.RebuildMode;
import org.opends.server.backends.VerifyConfig;
import org.opends.server.backends.pluggable.spi.AccessMode;
import org.opends.server.backends.pluggable.spi.ReadOnlyStorageException;
import org.opends.server.backends.pluggable.spi.ReadOperation;
@@ -71,7 +73,12 @@
import org.opends.server.backends.pluggable.spi.TreeName;
import org.opends.server.backends.pluggable.spi.WriteOperation;
import org.opends.server.backends.pluggable.spi.WriteableTransaction;
import org.opends.server.core.AddOperation;
import org.opends.server.core.DeleteOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.ModifyOperation;
import org.opends.server.core.SearchOperation;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.protocols.internal.SearchRequest;
@@ -85,6 +92,7 @@
import org.opends.server.types.LDIFImportConfig;
import org.opends.server.types.Modification;
import org.opends.server.types.RestoreConfig;
import org.opends.server.types.SearchFilter;
import org.opends.server.types.SearchResultEntry;
import org.opends.server.workflowelement.localbackend.LocalBackendSearchOperation;
import org.testng.Reporter;
@@ -555,9 +563,10 @@
  private void addEntriesToBackend(List<Entry> entries) throws Exception
  {
    AddOperation op = mock(AddOperation.class);
    for (Entry newEntry : entries)
    {
      backend.addEntry(newEntry, null);
      backend.addEntry(newEntry, op);
    }
  }
@@ -599,7 +608,8 @@
    backend.getRootContainer().checkForEnoughResources(null);
  }
  @Test(expectedExceptions = DirectoryException.class)
  @Test(expectedExceptions = DirectoryException.class,
      expectedExceptionsMessageRegExp="The entry .* cannot be added because its parent entry does not exist")
  public void testAddNoParent() throws Exception
  {
    Entry newEntry = TestCaseUtils.makeEntry("dn: " + badEntryDN, "objectclass: ou", "");
@@ -667,10 +677,43 @@
    Entry newEntry = oldEntry.duplicate(false);
    modifyAttribute = DirectoryServer.getAttributeTypeOrNull("jpegphoto");
    newEntry.applyModifications(Arrays.asList(new Modification(ADD, create(modifyAttribute, modifyValue))));
    List<Modification> mods = Arrays.asList(
        // unindexed
        new Modification(ADD, create(modifyAttribute, modifyValue)),
        // indexed
        new Modification(REPLACE, create("sn", "Smith")));
    newEntry.applyModifications(mods);
    backend.replaceEntry(oldEntry, newEntry, null);
    ModifyOperation modifyOp = mock(ModifyOperation.class);
    when(modifyOp.getModifications()).thenReturn(mods);
    backend.replaceEntry(oldEntry, newEntry, modifyOp);
    assertTrue(backend.getEntry(oldEntry.getName()).hasValue(modifyAttribute, null, modifyValue));
    final List<Entry> returnedEntries = new ArrayList<>();
    backend.search(createSearchOperation(
        newEntry.getName().parent(), SearchScope.WHOLE_SUBTREE, "(&(sn=Smith)(jpegphoto=foo))", returnedEntries));
    assertThat(returnedEntries).hasSize(1);
    assertThat(returnedEntries.get(0).getName()).isEqualTo(newEntry.getName());
  }
  private SearchOperation createSearchOperation(DN baseDN, SearchScope scope, String searchFilter,
      final List<Entry> returnedEntries) throws DirectoryException
  {
    SearchOperation searchOp = mock(SearchOperation.class);
    when(searchOp.getBaseDN()).thenReturn(baseDN);
    when(searchOp.getScope()).thenReturn(scope);
    when(searchOp.getFilter()).thenReturn(SearchFilter.createFilterFromString(searchFilter));
    when(searchOp.getClientConnection()).thenReturn(new ClientConnectionStub());
    doAnswer(new Answer<Object>()
    {
      @Override
      public Object answer(InvocationOnMock invocation) throws Throwable
      {
        returnedEntries.add(invocation.getArgumentAt(0, Entry.class));
        return null;
      }
    }).when(searchOp).returnEntry(any(Entry.class), any(List.class));
    return searchOp;
  }
  @Test
@@ -680,14 +723,15 @@
    DN prevDN = DN.valueOf("ou=People," + testBaseDN);
    DN newDN = DN.valueOf("ou=users," + testBaseDN);
    Entry renameEntry = backend.getEntry(prevDN).duplicate(false);
    ModifyDNOperation op = mock(ModifyDNOperation.class);
    renameEntry.setDN(newDN);
    backend.renameEntry(prevDN, renameEntry, null);
    backend.renameEntry(prevDN, renameEntry, op);
    Entry dbEntry = backend.getEntry(newDN);
    assertEquals(dbEntry.getName(), newDN, "Renamed entry is missing.");
    renameEntry.setDN(prevDN);
    backend.renameEntry(newDN, renameEntry, null);
    backend.renameEntry(newDN, renameEntry, op);
    dbEntry = backend.getEntry(prevDN);
    assertEquals(dbEntry.getName(), prevDN, "Original entry has not been renamed");
  }
@@ -699,18 +743,19 @@
    DN newDN = DN.valueOf("uid=USER.0,ou=People," + testBaseDN);
    Entry renameEntry = backend.getEntry(prevDN).duplicate(false);
    ModifyDNOperation op = mock(ModifyDNOperation.class);
    renameEntry.setDN(newDN);
    backend.renameEntry(prevDN, renameEntry, null);
    backend.renameEntry(prevDN, renameEntry, op);
    Entry dbEntry = backend.getEntry(newDN);
    assertEquals(dbEntry.getName().rdn().toString(), "uid=USER.0");
    renameEntry.setDN(prevDN);
    backend.renameEntry(newDN, renameEntry, null);
    backend.renameEntry(newDN, renameEntry, op);
    dbEntry = backend.getEntry(prevDN);
    assertEquals(dbEntry.getName().rdn().toString(), "uid=user.0");
  }
  @Test
  @Test(expectedExceptions = DirectoryException.class)
  public void testDeleteEntry() throws Exception
  {
    Entry deletedEntry = backend.getEntry(dnToDel).duplicate(false);
@@ -720,19 +765,17 @@
      deleteEntry(dnToDel);
      fail("Should have generated a DirectoryException");
    }
    catch (DirectoryException de)
    {
      // Expected exception, do nothing, test succeeds.
    }
    finally
    {
      backend.addEntry(deletedEntry, null);
      AddOperation op = mock(AddOperation.class);
      backend.addEntry(deletedEntry, op);
    }
  }
  private void deleteEntry(DN dn) throws Exception
  {
    backend.deleteEntry(dn, null);
    DeleteOperation op = mock(DeleteOperation.class);
    backend.deleteEntry(dn, op);
    assertNull(backend.getEntry(workEntries.get(1).getName()));
  }