From a4a5cd8e4c89ba459c1105f4b25a499895a3a571 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Fri, 09 Oct 2026 07:20:12 +0000
Subject: [PATCH] [#1180] Report the fail-over failure of the Grizzly proxy listener tests instead of timing out (#1181)

---
 opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPListenerTestCase.java |  159 +++++++++++++++++++++++++++-------------------------
 1 files changed, 83 insertions(+), 76 deletions(-)

diff --git a/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPListenerTestCase.java b/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPListenerTestCase.java
index fae5bbd..e340003 100644
--- a/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPListenerTestCase.java
+++ b/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPListenerTestCase.java
@@ -204,6 +204,39 @@
         return socket;
     }
 
+    /**
+     * Fails over the way a proxy does: connects to a free port, which must refuse the connection,
+     * then to the online server.
+     */
+    private static void failOverToOnlineServer(final InetSocketAddress onlineAddress) throws LdapException {
+        // The numeric host avoids a forward lookup of "localhost".
+        final InetSocketAddress offlineAddress = findFreeSocketAddress();
+        final LDAPConnectionFactory offlineFactory =
+                new LDAPConnectionFactory(offlineAddress.getAddress().getHostAddress(), offlineAddress.getPort());
+        try {
+            offlineFactory.getConnection().close();
+        } catch (final ConnectionException expected) {
+            // This is expected - so go to online server.
+            final LDAPConnectionFactory onlineFactory =
+                    new LDAPConnectionFactory(onlineAddress.getHostString(), onlineAddress.getPort());
+            try {
+                onlineFactory.getConnection().close();
+                return;
+            } catch (final Exception e) {
+                throw newLdapException(ResultCode.OTHER,
+                        "Unexpected exception when connecting to online server", e);
+            } finally {
+                onlineFactory.close();
+            }
+        } catch (final Exception e) {
+            throw newLdapException(ResultCode.OTHER,
+                    "Unexpected exception when connecting to offline server", e);
+        } finally {
+            offlineFactory.close();
+        }
+        throw newLdapException(ResultCode.OTHER, "Connection to offline server succeeded unexpectedly");
+    }
+
     /** Disables logging before the tests. */
     @BeforeClass
     public void disableLogging() {
@@ -534,7 +567,7 @@
      * @throws Exception
      *             If an unexpected exception occurred.
      */
-    @Test
+    @Test(timeOut = 60000)
     public void testLDAPListenerProxyDuringHandleAccept() throws Exception {
         final MockServerConnection onlineServerConnection = new MockServerConnection();
         final MockServerConnectionFactory onlineServerConnectionFactory =
@@ -552,39 +585,19 @@
                         @Override
                         public ServerConnection<Integer> handleAccept(
                                 final LDAPClientContext clientContext) throws LdapException {
-                            // First attempt offline server.
-                            InetSocketAddress offlineAddress = findFreeSocketAddress();
-                            LDAPConnectionFactory lcf =
-                                    new LDAPConnectionFactory(offlineAddress.getHostName(),
-                                            offlineAddress.getPort());
                             try {
-                                // This is expected to fail.
-                                lcf.getConnection().close();
-                                throw newLdapException(ResultCode.OTHER,
-                                        "Connection to offline server succeeded unexpectedly");
-                            } catch (final ConnectionException ce) {
-                                // This is expected - so go to online server.
-                                try {
-                                    lcf =
-                                            new LDAPConnectionFactory(
-                                                        onlineServerAddr.getHostName(),
-                                                        onlineServerAddr.getPort());
-                                    lcf.getConnection().close();
-                                } catch (final Exception e) {
-                                    // Unexpected.
-                                    throw newLdapException(
-                                                    ResultCode.OTHER,
-                                                    "Unexpected exception when connecting to online server",
-                                                    e);
-                                }
-                            } catch (final Exception e) {
-                                // Unexpected.
-                                throw newLdapException(
-                                                ResultCode.OTHER,
-                                                "Unexpected exception when connecting to offline server",
-                                                e);
+                                failOverToOnlineServer(onlineServerAddr);
+                            } catch (final LdapException e) {
+                                // The listener only closes the client connection when handleAccept
+                                // fails: report the failure through the context the test waits for,
+                                // instead of leaving that wait to time out without a cause.
+                                proxyServerConnection.context.handleException(e);
+                                throw e;
+                            } catch (final RuntimeException e) {
+                                proxyServerConnection.context.handleException(
+                                        newLdapException(ResultCode.OTHER, e));
+                                throw e;
                             }
-
                             return super.handleAccept(clientContext);
                         }
 
@@ -593,23 +606,28 @@
             final LDAPListener proxyListener = new LDAPListener(Collections.singleton(loopbackWithDynamicPort()),
                     new ServerConnectionFactoryAdapter(Options.defaultOptions().get(LDAP_DECODE_OPTIONS),
                             proxyServerConnectionFactory));
+            // Connect to the proxy listener (not to the online server
+            // directly, otherwise the proxy handleAccept is never invoked)
+            // and close.
+            final InetSocketAddress proxyAddr = proxyListener.firstSocketAddress();
+            final LDAPConnectionFactory proxyClientFactory =
+                    new LDAPConnectionFactory(proxyAddr.getHostString(), proxyAddr.getPort());
             try {
-                // Connect to the proxy listener (not to the online server
-                // directly, otherwise the proxy handleAccept is never invoked)
-                // and close.
-                final InetSocketAddress proxyAddr = proxyListener.firstSocketAddress();
-                final Connection connection =
-                        new LDAPConnectionFactory(proxyAddr.getHostName(),
-                            proxyAddr.getPort()).getConnection();
-
-                assertThat(proxyServerConnection.context.get(10, TimeUnit.SECONDS)).isNotNull();
-                assertThat(onlineServerConnection.context.get(10, TimeUnit.SECONDS)).isNotNull();
-
-                connection.close();
+                final Connection connection = proxyClientFactory.getConnection();
+                try {
+                    // handleAccept makes both fail-over connections before it resolves the context,
+                    // and each of them may take up to the default connect timeout (10 seconds):
+                    // wait longer than that, so that a failed attempt reports its own cause.
+                    assertThat(proxyServerConnection.context.get(30, TimeUnit.SECONDS)).isNotNull();
+                    assertThat(onlineServerConnection.context.get(10, TimeUnit.SECONDS)).isNotNull();
+                } finally {
+                    connection.close();
+                }
 
                 // Wait for connect/close to complete.
-                proxyServerConnection.isClosed.await();
+                assertThat(proxyServerConnection.isClosed.await(10, TimeUnit.SECONDS)).isTrue();
             } finally {
+                proxyClientFactory.close();
                 proxyListener.close();
             }
         } finally {
@@ -624,7 +642,7 @@
      * @throws Exception
      *             If an unexpected exception occurred.
      */
-    @Test(timeOut = 10000)
+    @Test(timeOut = 60000)
     public void testLDAPListenerProxyDuringHandleBind() throws Exception {
         final MockServerConnection onlineServerConnection = new MockServerConnection();
         final MockServerConnectionFactory onlineServerConnectionFactory =
@@ -643,34 +661,22 @@
                         final IntermediateResponseHandler intermediateResponseHandler,
                         final LdapResultHandler<BindResult> resultHandler)
                         throws UnsupportedOperationException {
-                    // First attempt offline server.
-                    InetSocketAddress offlineAddress = findFreeSocketAddress();
-                    LDAPConnectionFactory lcf = new LDAPConnectionFactory(offlineAddress.getHostName(),
-                            offlineAddress.getPort());
                     try {
-                        // This is expected to fail.
-                        lcf.getConnection().close();
-                        resultHandler.handleException(newLdapException(
-                                ResultCode.OTHER,
-                                "Connection to offline server succeeded unexpectedly"));
-                    } catch (final ConnectionException ce) {
-                        // This is expected - so go to online server.
-                        try {
-                            lcf = new LDAPConnectionFactory(onlineServerAddr.getHostName(),
-                                onlineServerAddr.getPort());
-                            lcf.getConnection().close();
-                            resultHandler.handleResult(Responses.newBindResult(ResultCode.SUCCESS));
-                        } catch (final Exception e) {
-                            // Unexpected.
-                            resultHandler.handleException(newLdapException(
-                                    ResultCode.OTHER,
-                                    "Unexpected exception when connecting to online server", e));
-                        }
-                    } catch (final Exception e) {
-                        // Unexpected.
-                        resultHandler.handleException(newLdapException(
-                                ResultCode.OTHER,
-                                "Unexpected exception when connecting to offline server", e));
+                        failOverToOnlineServer(onlineServerAddr);
+                        resultHandler.handleResult(Responses.newBindResult(ResultCode.SUCCESS));
+                    } catch (final LdapException e) {
+                        // A bind must fail with a bind result: the listener cannot encode any other
+                        // result as a bind response, and would then never answer the bind. Only the
+                        // diagnostic message reaches the client, so it carries the nested cause.
+                        final Throwable cause = e.getCause();
+                        final String message = cause != null
+                                ? e.getResult().getDiagnosticMessage() + ": " + cause
+                                : e.getResult().getDiagnosticMessage();
+                        resultHandler.handleException(newLdapException(Responses.newBindResult(ResultCode.OTHER)
+                                .setDiagnosticMessage(message).setCause(e)));
+                    } catch (final RuntimeException e) {
+                        resultHandler.handleException(newLdapException(Responses.newBindResult(ResultCode.OTHER)
+                                .setDiagnosticMessage(e.toString()).setCause(e)));
                     }
                 }
 
@@ -681,11 +687,11 @@
                     new ServerConnectionFactoryAdapter(Options.defaultOptions().get(LDAP_DECODE_OPTIONS),
                             proxyServerConnectionFactory));
             final InetSocketAddress proxyAddr = proxyListener.firstSocketAddress();
+            final LDAPConnectionFactory proxyClientFactory =
+                    new LDAPConnectionFactory(proxyAddr.getHostString(), proxyAddr.getPort());
             try {
                 // Connect, bind, and close.
-                final Connection connection =
-                        new LDAPConnectionFactory(proxyAddr.getHostName(),
-                            proxyAddr.getPort()).getConnection();
+                final Connection connection = proxyClientFactory.getConnection();
                 try {
                     connection.bind("cn=test", "password".toCharArray());
 
@@ -699,6 +705,7 @@
                 // Wait for connect/close to complete.
                 proxyServerConnection.isClosed.await();
             } finally {
+                proxyClientFactory.close();
                 proxyListener.close();
             }
         } finally {

--
Gitblit v1.10.0