/* * 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 * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * 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 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. 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 2006-2008 Sun Microsystems, Inc. * Portions copyright 2011 ForgeRock AS. */ package org.opends.server.core; import static org.opends.server.util.ServerConstants.OID_WHO_AM_I_REQUEST; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; import java.net.Socket; import java.util.ArrayList; import java.util.LinkedHashSet; import org.opends.server.TestCaseUtils; import org.opends.server.tools.LDAPWriter; import org.opends.server.tools.LDAPReader; import org.opends.messages.Message; import org.opends.server.plugins.DelayPreOpPlugin; import org.opends.server.plugins.DisconnectClientPlugin; import org.opends.server.protocols.internal.InternalClientConnection; import org.opends.server.protocols.ldap.AbandonRequestProtocolOp; import org.opends.server.protocols.ldap.AddRequestProtocolOp; import org.opends.server.protocols.ldap.AddResponseProtocolOp; import org.opends.server.protocols.ldap.BindRequestProtocolOp; import org.opends.server.protocols.ldap.BindResponseProtocolOp; import org.opends.server.protocols.ldap.CompareRequestProtocolOp; import org.opends.server.protocols.ldap.CompareResponseProtocolOp; import org.opends.server.protocols.ldap.DeleteRequestProtocolOp; import org.opends.server.protocols.ldap.DeleteResponseProtocolOp; import org.opends.server.protocols.ldap.ExtendedRequestProtocolOp; import org.opends.server.protocols.ldap.ExtendedResponseProtocolOp; import org.opends.server.protocols.ldap.LDAPAttribute; import org.opends.server.protocols.ldap.LDAPFilter; import org.opends.server.protocols.ldap.LDAPMessage; import org.opends.server.protocols.ldap.LDAPModification; import org.opends.server.protocols.ldap.LDAPResultCode; import org.opends.server.protocols.ldap.ModifyDNRequestProtocolOp; import org.opends.server.protocols.ldap.ModifyDNResponseProtocolOp; import org.opends.server.protocols.ldap.ModifyRequestProtocolOp; import org.opends.server.protocols.ldap.ModifyResponseProtocolOp; import org.opends.server.protocols.ldap.SearchRequestProtocolOp; import org.opends.server.protocols.ldap.SearchResultDoneProtocolOp; import org.opends.server.types.*; import org.testng.annotations.Test; import org.testng.annotations.BeforeClass; /** * A set of test cases for abandon operations */ public class AbandonOperationTestCase extends OperationTestCase { /** * {@inheritDoc} */ @Override() protected Operation[] createTestOperations() throws Exception { InternalClientConnection conn = InternalClientConnection.getRootConnection(); return new Operation[] { new AbandonOperationBasis(conn, InternalClientConnection.nextOperationID(), InternalClientConnection.nextMessageID(), new ArrayList<Control>(), 1) }; } /** * For some reason, the @BeforeClass method in the super class is not called. */ @BeforeClass() public void startServer() throws Exception { super.startServer(); } /** * Tests the <CODE>getIDToAbandon</CODE> method. */ @Test() public void testGetIDToAbandon() { InternalClientConnection conn = InternalClientConnection.getRootConnection(); AbandonOperationBasis abandonOperation = new AbandonOperationBasis(conn, InternalClientConnection.nextOperationID(), InternalClientConnection.nextMessageID(), new ArrayList<Control>(), 1); assertEquals(abandonOperation.getIDToAbandon(), 1); } /** * Tests the <CODE>cancel</CODE> method. */ @Test() public void testCancel() { InternalClientConnection conn = InternalClientConnection.getRootConnection(); AbandonOperationBasis abandonOperation = new AbandonOperationBasis(conn, InternalClientConnection.nextOperationID(), InternalClientConnection.nextMessageID(), new ArrayList<Control>(), 1); CancelRequest cancelRequest = new CancelRequest(true, Message.raw("Test Cancel")); assertEquals(abandonOperation.cancel(cancelRequest).getResultCode(), ResultCode.CANNOT_CANCEL); } /** * Tests the <CODE>getCancelRequest</CODE> method. */ @Test() public void testGetCancelRequest() { InternalClientConnection conn = InternalClientConnection.getRootConnection(); AbandonOperationBasis abandonOperation = new AbandonOperationBasis(conn, InternalClientConnection.nextOperationID(), InternalClientConnection.nextMessageID(), new ArrayList<Control>(), 1); assertNull(abandonOperation.getCancelRequest()); } /** * Invokes a number of operation methods on the provided abandon operation * for which all processing has been completed. * * @param abandonOperation The operation to be tested. */ private void examineCompletedOperation(AbandonOperation abandonOperation) { assertTrue(abandonOperation.getIDToAbandon() > 0); assertTrue(abandonOperation.getProcessingStartTime() > 0); assertTrue(abandonOperation.getProcessingStopTime() > 0); assertTrue(abandonOperation.getProcessingTime() >= 0); assertNotNull(abandonOperation.getResponseLogElements()); } /** * Attempts an internal abandon operation, which will fail because internal * operations cannot be abandoned. */ @Test() public void testAbandonInternal() { InternalClientConnection conn = InternalClientConnection.getRootConnection(); AbandonOperationBasis abandonOperation = new AbandonOperationBasis(conn, InternalClientConnection.nextOperationID(), InternalClientConnection.nextMessageID(), new ArrayList<Control>(), 1); abandonOperation.run(); assertEquals(abandonOperation.getResultCode(), ResultCode.CANNOT_CANCEL); examineCompletedOperation(abandonOperation); } /** * Tests performing an abandon operation on a client connection that gets * terminated during pre-parse plugin processing. * * @throws Exception If an unexpected problem occurs. */ @Test(groups = { "slow" }) public void testDisconnectInPreParse() throws Exception { // Establish a connection to the server. It can be unauthenticated for the // purpose of this test. Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort()); LDAPWriter w = new LDAPWriter(s); // Send the abandon request to the server and wait a few seconds to ensure // it has completed before closing the connection. AbandonRequestProtocolOp abandonRequest = new AbandonRequestProtocolOp(1); LDAPMessage message = new LDAPMessage(2, abandonRequest, DisconnectClientPlugin.createDisconnectControlList("PreParse")); w.writeMessage(message); Thread.sleep(3000); try { s.close(); } catch (Exception e) {} // NOTE: We can't check to see if pre-parse plugins were called yet // because there's no plugin ordering. It's possible that the // disconnect plugin was called before the invocation counter plugin, // in which case the pre-parse count wouldn't be incremented. } /** * Tests the use of the abandon operation with a target operation that doesn't * exist. * * @throws Exception If an unexpected problem occurs. */ @Test(groups = { "slow" }) public void testNoSuchOperation() throws Exception { // Establish a connection to the server. It can be unauthenticated for the // purpose of this test. Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort()); LDAPWriter w = new LDAPWriter(s); // Send the abandon request to the server and wait a few seconds to ensure // it has completed before closing the connection. AbandonRequestProtocolOp abandonRequest = new AbandonRequestProtocolOp(1); w.writeMessage(new LDAPMessage(2, abandonRequest)); Thread.sleep(3000); s.close(); } /** * Tests the ability to abandon an add operation. * * @throws Exception If an unexpected problem occurs. */ @Test() public void testAbandonAdd() throws Exception { TestCaseUtils.initializeTestBackend(true); // Establish a connection to the server and bind as a root user. Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort()); LDAPReader r = new LDAPReader(s); LDAPWriter w = new LDAPWriter(s); TestCaseUtils.configureSocket(s); BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"), 3, ByteString.valueOf("password")); LDAPMessage message = new LDAPMessage(1, bindRequest); w.writeMessage(message); message = r.readMessage(); BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp(); assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS); long abandonRequests = ldapStatistics.getAbandonRequests(); long abandonsCompleted = ldapStatistics.getOperationsAbandoned(); // Create an add request and send it to the server. Make sure to include // the delay request control so it won't complete before we can send the // abandon request. ArrayList<RawAttribute> attributes = new ArrayList<RawAttribute>(); ArrayList<ByteString> values = new ArrayList<ByteString>(2); values.add(ByteString.valueOf("top")); values.add(ByteString.valueOf("organizationalUnit")); attributes.add(new LDAPAttribute("objectClass", values)); values = new ArrayList<ByteString>(1); values.add(ByteString.valueOf("People")); attributes.add(new LDAPAttribute("ou", values)); AddRequestProtocolOp addRequest = new AddRequestProtocolOp(ByteString.valueOf("ou=People,o=test"), attributes); message = new LDAPMessage(2, addRequest, DelayPreOpPlugin.createDelayControlList(5000)); w.writeMessage(message); // Send the abandon request to the server. AbandonRequestProtocolOp abandonRequest = new AbandonRequestProtocolOp(2); w.writeMessage(new LDAPMessage(3, abandonRequest)); // Normally, abandoned operations don't receive a response. However, the // testing configuration has been updated to ensure that if an operation // does get abandoned, the server will return a response for it with a // result code of "cancelled". message = r.readMessage(); AddResponseProtocolOp addResponse = message.getAddResponseProtocolOp(); assertEquals(addResponse.getResultCode(), LDAPResultCode.CANCELED); assertEquals(ldapStatistics.getAbandonRequests(), abandonRequests+1); waitForAbandon(abandonsCompleted+1); s.close(); } /** * Tests the ability to abandon a compare operation. * * @throws Exception If an unexpected problem occurs. */ @Test() public void testAbandonCompare() throws Exception { TestCaseUtils.initializeTestBackend(true); // Establish a connection to the server and bind as a root user. Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort()); LDAPReader r = new LDAPReader(s); LDAPWriter w = new LDAPWriter(s); TestCaseUtils.configureSocket(s); BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"), 3, ByteString.valueOf("password")); LDAPMessage message = new LDAPMessage(1, bindRequest); w.writeMessage(message); message = r.readMessage(); BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp(); assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS); long abandonRequests = ldapStatistics.getAbandonRequests(); long abandonsCompleted = ldapStatistics.getOperationsAbandoned(); // Create a compare request and send it to the server. Make sure to include // the delay request control so it won't complete before we can send the // abandon request. CompareRequestProtocolOp compareRequest = new CompareRequestProtocolOp(ByteString.valueOf("o=test"), "o", ByteString.valueOf("test")); message = new LDAPMessage(2, compareRequest, DelayPreOpPlugin.createDelayControlList(5000)); w.writeMessage(message); // Send the abandon request to the server and wait a few seconds to ensure // it has completed before closing the connection. AbandonRequestProtocolOp abandonRequest = new AbandonRequestProtocolOp(2); w.writeMessage(new LDAPMessage(3, abandonRequest)); // Normally, abandoned operations don't receive a response. However, the // testing configuration has been updated to ensure that if an operation // does get abandoned, the server will return a response for it with a // result code of "cancelled". message = r.readMessage(); CompareResponseProtocolOp compareResponse = message.getCompareResponseProtocolOp(); assertEquals(compareResponse.getResultCode(), LDAPResultCode.CANCELED); assertEquals(ldapStatistics.getAbandonRequests(), abandonRequests+1); waitForAbandon(abandonsCompleted+1); s.close(); } /** * Tests the ability to abandon a delete operation. * * @throws Exception If an unexpected problem occurs. */ @Test() public void testAbandonDelete() throws Exception { TestCaseUtils.initializeTestBackend(true); // Add an entry to the server that we can delete. Entry e = TestCaseUtils.makeEntry( "dn: cn=test,o=test", "objectClass: top", "objectClass: device", "cn: test"); InternalClientConnection conn = InternalClientConnection.getRootConnection(); AddOperation addOperation = conn.processAdd(e.getDN(), e.getObjectClasses(), e.getUserAttributes(), e.getOperationalAttributes()); assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); // Establish a connection to the server and bind as a root user. Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort()); LDAPReader r = new LDAPReader(s); LDAPWriter w = new LDAPWriter(s); TestCaseUtils.configureSocket(s); BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"), 3, ByteString.valueOf("password")); LDAPMessage message = new LDAPMessage(1, bindRequest); w.writeMessage(message); message = r.readMessage(); BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp(); assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS); long abandonRequests = ldapStatistics.getAbandonRequests(); long abandonsCompleted = ldapStatistics.getOperationsAbandoned(); // Create a delete request and send it to the server. Make sure to include // the delay request control so it won't complete before we can send the // abandon request. DeleteRequestProtocolOp deleteRequest = new DeleteRequestProtocolOp(ByteString.valueOf("cn=test,o=test")); message = new LDAPMessage(2, deleteRequest, DelayPreOpPlugin.createDelayControlList(5000)); w.writeMessage(message); // Send the abandon request to the server and wait a few seconds to ensure // it has completed before closing the connection. AbandonRequestProtocolOp abandonRequest = new AbandonRequestProtocolOp(2); w.writeMessage(new LDAPMessage(3, abandonRequest)); // Normally, abandoned operations don't receive a response. However, the // testing configuration has been updated to ensure that if an operation // does get abandoned, the server will return a response for it with a // result code of "cancelled". message = r.readMessage(); DeleteResponseProtocolOp deleteResponse = message.getDeleteResponseProtocolOp(); assertEquals(deleteResponse.getResultCode(), LDAPResultCode.CANCELED); assertEquals(ldapStatistics.getAbandonRequests(), abandonRequests+1); waitForAbandon(abandonsCompleted+1); s.close(); } /** * Tests the ability to abandon an extended operation. * * @throws Exception If an unexpected problem occurs. */ @Test() public void testAbandonExtended() throws Exception { TestCaseUtils.initializeTestBackend(true); // Establish a connection to the server and bind as a root user. Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort()); LDAPReader r = new LDAPReader(s); LDAPWriter w = new LDAPWriter(s); TestCaseUtils.configureSocket(s); BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"), 3, ByteString.valueOf("password")); LDAPMessage message = new LDAPMessage(1, bindRequest); w.writeMessage(message); message = r.readMessage(); BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp(); assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS); long abandonRequests = ldapStatistics.getAbandonRequests(); long abandonsCompleted = ldapStatistics.getOperationsAbandoned(); // Create a "Who Am I?" extended operation and send it to the server. Make // sure to include the delay request control so it won't complete before we // can send the abandon request. ExtendedRequestProtocolOp whoAmIRequest = new ExtendedRequestProtocolOp(OID_WHO_AM_I_REQUEST, null); message = new LDAPMessage(2, whoAmIRequest, DelayPreOpPlugin.createDelayControlList(5000)); w.writeMessage(message); // Send the abandon request to the server and wait a few seconds to ensure // it has completed before closing the connection. AbandonRequestProtocolOp abandonRequest = new AbandonRequestProtocolOp(2); w.writeMessage(new LDAPMessage(3, abandonRequest)); // Normally, abandoned operations don't receive a response. However, the // testing configuration has been updated to ensure that if an operation // does get abandoned, the server will return a response for it with a // result code of "cancelled". message = r.readMessage(); ExtendedResponseProtocolOp extendedResponse = message.getExtendedResponseProtocolOp(); assertEquals(extendedResponse.getResultCode(), LDAPResultCode.CANCELED); assertEquals(ldapStatistics.getAbandonRequests(), abandonRequests+1); waitForAbandon(abandonsCompleted+1); s.close(); } /** * Tests the ability to abandon a modify operation. * * @throws Exception If an unexpected problem occurs. */ @Test() public void testAbandonModify() throws Exception { TestCaseUtils.initializeTestBackend(true); // Establish a connection to the server and bind as a root user. Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort()); LDAPReader r = new LDAPReader(s); LDAPWriter w = new LDAPWriter(s); TestCaseUtils.configureSocket(s); BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"), 3, ByteString.valueOf("password")); LDAPMessage message = new LDAPMessage(1, bindRequest); w.writeMessage(message); message = r.readMessage(); BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp(); assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS); long abandonRequests = ldapStatistics.getAbandonRequests(); long abandonsCompleted = ldapStatistics.getOperationsAbandoned(); // Create a modify request and send it to the server. Make sure to include // the delay request control so it won't complete before we can send the // abandon request. ArrayList<ByteString> values = new ArrayList<ByteString>(1); values.add(ByteString.valueOf("foo")); ArrayList<RawModification> mods = new ArrayList<RawModification>(1); mods.add(new LDAPModification(ModificationType.REPLACE, new LDAPAttribute("description", values))); ModifyRequestProtocolOp modifyRequest = new ModifyRequestProtocolOp(ByteString.valueOf("o=test"), mods); message = new LDAPMessage(2, modifyRequest, DelayPreOpPlugin.createDelayControlList(5000)); w.writeMessage(message); // Send the abandon request to the server and wait a few seconds to ensure // it has completed before closing the connection. AbandonRequestProtocolOp abandonRequest = new AbandonRequestProtocolOp(2); w.writeMessage(new LDAPMessage(3, abandonRequest)); // Normally, abandoned operations don't receive a response. However, the // testing configuration has been updated to ensure that if an operation // does get abandoned, the server will return a response for it with a // result code of "cancelled". message = r.readMessage(); ModifyResponseProtocolOp modifyResponse = message.getModifyResponseProtocolOp(); assertEquals(modifyResponse.getResultCode(), LDAPResultCode.CANCELED); assertEquals(ldapStatistics.getAbandonRequests(), abandonRequests+1); waitForAbandon(abandonsCompleted+1); s.close(); } /** * Tests the ability to abandon a modify DN operation. * * @throws Exception If an unexpected problem occurs. */ @Test() public void testAbandonModifyDN() throws Exception { TestCaseUtils.initializeTestBackend(true); // Add an entry to the server that we can rename. Entry e = TestCaseUtils.makeEntry( "dn: cn=test,o=test", "objectClass: top", "objectClass: device", "cn: test"); InternalClientConnection conn = InternalClientConnection.getRootConnection(); AddOperation addOperation = conn.processAdd(e.getDN(), e.getObjectClasses(), e.getUserAttributes(), e.getOperationalAttributes()); assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); // Establish a connection to the server and bind as a root user. Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort()); LDAPReader r = new LDAPReader(s); LDAPWriter w = new LDAPWriter(s); TestCaseUtils.configureSocket(s); BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"), 3, ByteString.valueOf("password")); LDAPMessage message = new LDAPMessage(1, bindRequest); w.writeMessage(message); message = r.readMessage(); BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp(); assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS); long abandonRequests = ldapStatistics.getAbandonRequests(); long abandonsCompleted = ldapStatistics.getOperationsAbandoned(); // Create a modify DN request and send it to the server. Make sure to // include the delay request control so it won't complete before we can send // the abandon request. ModifyDNRequestProtocolOp modifyDNRequest = new ModifyDNRequestProtocolOp(ByteString.valueOf("cn=test,o=test"), ByteString.valueOf("cn=test2"), true); message = new LDAPMessage(2, modifyDNRequest, DelayPreOpPlugin.createDelayControlList(5000)); w.writeMessage(message); // Send the abandon request to the server and wait a few seconds to ensure // it has completed before closing the connection. AbandonRequestProtocolOp abandonRequest = new AbandonRequestProtocolOp(2); w.writeMessage(new LDAPMessage(3, abandonRequest)); // Normally, abandoned operations don't receive a response. However, the // testing configuration has been updated to ensure that if an operation // does get abandoned, the server will return a response for it with a // result code of "cancelled". message = r.readMessage(); ModifyDNResponseProtocolOp modifyDNResponse = message.getModifyDNResponseProtocolOp(); assertEquals(modifyDNResponse.getResultCode(), LDAPResultCode.CANCELED); assertEquals(ldapStatistics.getAbandonRequests(), abandonRequests+1); waitForAbandon(abandonsCompleted+1); s.close(); } /** * Tests the ability to abandon a search operation. * * @throws Exception If an unexpected problem occurs. */ @Test() public void testAbandonSearch() throws Exception { TestCaseUtils.initializeTestBackend(true); // Establish a connection to the server and bind as a root user. Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort()); LDAPReader r = new LDAPReader(s); LDAPWriter w = new LDAPWriter(s); TestCaseUtils.configureSocket(s); BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"), 3, ByteString.valueOf("password")); LDAPMessage message = new LDAPMessage(1, bindRequest); w.writeMessage(message); message = r.readMessage(); BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp(); assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS); long abandonRequests = ldapStatistics.getAbandonRequests(); long abandonsCompleted = ldapStatistics.getOperationsAbandoned(); // Create a search request and send it to the server. Make sure to include // the delay request control so it won't complete before we can send the // abandon request. SearchRequestProtocolOp searchRequest = new SearchRequestProtocolOp(ByteString.valueOf("o=test"), SearchScope.BASE_OBJECT, DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, LDAPFilter.decode("(match=false)"), new LinkedHashSet<String>()); message = new LDAPMessage(2, searchRequest, DelayPreOpPlugin.createDelayControlList(5000)); w.writeMessage(message); // Send the abandon request to the server and wait a few seconds to ensure // it has completed before closing the connection. AbandonRequestProtocolOp abandonRequest = new AbandonRequestProtocolOp(2); w.writeMessage(new LDAPMessage(3, abandonRequest)); // Normally, abandoned operations don't receive a response. However, the // testing configuration has been updated to ensure that if an operation // does get abandoned, the server will return a response for it with a // result code of "cancelled". message = r.readMessage(); SearchResultDoneProtocolOp searchDone = message.getSearchResultDoneProtocolOp(); assertEquals(searchDone.getResultCode(), LDAPResultCode.CANCELED); assertEquals(ldapStatistics.getAbandonRequests(), abandonRequests+1); waitForAbandon(abandonsCompleted+1); s.close(); } /** * Waits up to ten seconds for the abandoned operation count to reach the * expected value. * * @param expectedCount The abandon count the server is expected to reach. * * @throws Exception If an unexpected problem occurs. */ private void waitForAbandon(long expectedCount) throws Exception { long stopTime = System.currentTimeMillis() + 10000; while (System.currentTimeMillis() < stopTime) { if (ldapStatistics.getOperationsAbandoned() == expectedCount) { return; } Thread.sleep(10); } throw new AssertionError("Expected abandon count of " + expectedCount + " but got " + ldapStatistics.getOperationsAbandoned()); } }