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())); }