@Test(description = "OPENDJ-1197")
  public void testClientSideConnectTimeout() throws Exception {
    // Use an non-local unreachable network address.
    final ConnectionFactory factory =
        new LDAPConnectionFactory(
            "10.20.30.40", 1389, new LDAPOptions().setConnectTimeout(1, TimeUnit.MILLISECONDS));
    try {
      for (int i = 0; i < ITERATIONS; i++) {
        final PromiseImpl<LdapException, NeverThrowsException> promise = PromiseImpl.create();
        final Promise<? extends Connection, LdapException> connectionPromise =
            factory.getConnectionAsync();
        connectionPromise.onFailure(getFailureHandler(promise));

        ConnectionException e =
            (ConnectionException) promise.getOrThrow(TEST_TIMEOUT, TimeUnit.SECONDS);
        assertThat(e.getResult().getResultCode()).isEqualTo(ResultCode.CLIENT_SIDE_CONNECT_ERROR);
        // Wait for the connect to timeout.
        try {
          connectionPromise.getOrThrow(TEST_TIMEOUT, TimeUnit.SECONDS);
          fail("The connect request succeeded unexpectedly");
        } catch (ConnectionException ce) {
          assertThat(ce.getResult().getResultCode())
              .isEqualTo(ResultCode.CLIENT_SIDE_CONNECT_ERROR);
        }
      }
    } finally {
      factory.close();
    }
  }
  /**
   * Unit test for OPENDJ-1247: as per previous test, except this time verify that the connection
   * failure removes the connection from a connection pool.
   */
  @Test
  public void testClientSideTimeoutForBindRequestInConnectionPool() throws Exception {
    resetState();
    registerBindEvent();
    registerCloseEvent();

    for (int i = 0; i < ITERATIONS; i++) {
      final Connection connection = pool.getConnection();
      try {
        waitForConnect();
        final MockConnectionEventListener listener = new MockConnectionEventListener();
        connection.addConnectionEventListener(listener);

        // Now bind with timeout.
        final PromiseImpl<LdapException, NeverThrowsException> promise = PromiseImpl.create();
        final LdapPromise<BindResult> bindPromise = connection.bindAsync(newSimpleBindRequest());
        bindPromise.onFailure(getFailureHandler(promise));
        waitForBind();

        // Wait for the request to timeout and check the handler was invoked.
        TimeoutResultException e = (TimeoutResultException) promise.getOrThrow(5, TimeUnit.SECONDS);
        verifyResultCodeIsClientSideTimeout(e);

        // Now check the promise was completed as expected.
        try {
          bindPromise.getOrThrow(5, TimeUnit.SECONDS);
          fail("The bind request succeeded unexpectedly");
        } catch (TimeoutResultException te) {
          verifyResultCodeIsClientSideTimeout(te);
        }

        /*
         * The connection should no longer be valid, the event listener
         * should have been notified, but no abandon should have been
         * sent.
         */
        listener.awaitError(TEST_TIMEOUT, TimeUnit.SECONDS);
        assertThat(connection.isValid()).isFalse();
        verifyResultCodeIsClientSideTimeout(listener.getError());
        connection.close();
        waitForClose();
        verifyNoAbandonSent();
      } finally {
        connection.close();
      }
    }
  }
  /**
   * Unit test for OPENDJ-1247: a locally timed out request which is not a bind or startTLS should
   * result in a client side timeout error, but the connection should remain valid. In addition, no
   * abandon request should be sent.
   */
  @Test
  public void testClientSideTimeoutForSearchRequest() throws Exception {
    resetState();
    registerSearchEvent();
    registerAbandonEvent();

    for (int i = 0; i < ITERATIONS; i++) {
      final Connection connection = factory.getConnection();
      try {
        waitForConnect();
        final ConnectionEventListener listener = mock(ConnectionEventListener.class);
        connection.addConnectionEventListener(listener);
        final PromiseImpl<LdapException, NeverThrowsException> promise = PromiseImpl.create();
        final LdapPromise<SearchResultEntry> connectionPromise =
            connection.readEntryAsync(DN.valueOf("cn=test"), null);
        connectionPromise.onFailure(getFailureHandler(promise));
        waitForSearch();

        LdapException e = promise.getOrThrow(TEST_TIMEOUT, TimeUnit.SECONDS);
        verifyResultCodeIsClientSideTimeout(e);
        // Wait for the request to timeout.
        try {
          connectionPromise.getOrThrow(TEST_TIMEOUT, TimeUnit.SECONDS);
          fail("The search request succeeded unexpectedly");
        } catch (TimeoutResultException te) {
          verifyResultCodeIsClientSideTimeout(te);
        }

        // The connection should still be valid.
        assertThat(connection.isValid()).isTrue();
        verifyZeroInteractions(listener);
        /*
         * FIXME: The search should have been abandoned (see comment in
         * LDAPConnection for explanation).
         */
        // waitForAbandon();
      } finally {
        connection.close();
      }
    }
  }
 /** {@inheritDoc} */
 @Override
 public Promise<List<Resource>, ResourceException> apply(final ResourceException error) {
   List<Promise<Resource, ResourceException>> promises =
       new ArrayList<Promise<Resource, ResourceException>>();
   PromiseImpl<Resource, ResourceException> kicker = PromiseImpl.create();
   promises.add(kicker);
   for (String id : policyIds) {
     promises.add(policyResource.handleDelete(context, Requests.newDeleteRequest(id)));
   }
   Promise<List<Resource>, ResourceException> promise =
       Promises.when(promises)
           .thenAsync(
               new AsyncFunction<List<Resource>, List<Resource>, ResourceException>() {
                 @Override
                 public Promise<List<Resource>, ResourceException> apply(List<Resource> value) {
                   // If we succeed in deleting then return the original error
                   return Promises.newExceptionPromise(error);
                 }
               });
   kicker.handleResult(null);
   return promise;
 }