This is an automated email from the ASF dual-hosted git repository.

apupier pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 9ba6a0ac42e4 fix(camel-infinispan): fix test failures on Linux with 
Podman due to IPv6 loopback resolution
9ba6a0ac42e4 is described below

commit 9ba6a0ac42e4d4b51c848147d367f0c0001a050e
Author: AurĂ©lien Pupier <[email protected]>
AuthorDate: Wed Oct 7 11:03:36 2026 +0200

    fix(camel-infinispan): fix test failures on Linux with Podman due to
    IPv6 loopback resolution
    
    On Linux with Podman, containers are started in host-network mode so
    that port mappings work without a separate network namespace.  In that
    mode, Testcontainers' container.getHost() returns "localhost".  The
    JVM on recent Linux systems resolves "localhost" to the IPv6 loopback
    address (::1) before the IPv4 one (127.0.0.1), but the Infinispan
    server only binds on IPv4.  Every fresh RemoteCacheManager therefore
    failed its initial TCP connection with:
    
      TransportException: finishConnect(..) failed with error(-111):
      Connection refused: localhost/[0:0:0:0:0:0:0:1]:11222
    
    Three distinct problems were causing test failures:
    
    1. Initial connection uses the wrong address family
       All test helpers that built a ConfigurationBuilder passed
       service.host() (or service.getServiceAddress()) directly to
       .host(...) / setHosts(...).  This caused the IPv6 resolution.
    
       Fix: add a InfinispanRemoteTestSupport.resolvedHost(String) helper
       that maps "localhost" -> "127.0.0.1" and apply it at every call
       site:
         - InfinispanRemoteTestSupport.getConfiguration()
         - InfinispanRemoteKeyValueRepositoryIT.getConfiguration()
         - InfinispanRemoteClusteredTestSupport.createConfiguration()
         - InfinispanRemoteConfigurationIT.getBaseConfiguration()
         - 
SpringInfinispanRemoteIdempotentRepositoryTestSupport.setupResources()
         - 
InfinispanRemoteEmbeddingStoreIT.createInfinispanRemoteConfiguration()
    
    2. Topology-aware client intelligence re-resolves "localhost" to ::1
       When BASIC client intelligence was not set, the Hotrod client asked
       the server for a topology update after the initial connection and
       re-connected to the advertised address, which was again "localhost"
       -> ::1.  The conditional guard
         if (!Boolean.getBoolean(INFINISPAN_CONTAINER_NETWORK_MODE_HOST))
       wrongly skipped BASIC mode in host-network mode, meaning every new
       RemoteCacheManager created inside a @BeforeEach would fail on the
       topology-driven reconnect.
    
       Fix: always set BASIC client intelligence unconditionally in all
       test ConfigurationBuilders; remove the now-unused
       InfinispanProperties import.
    
    3. TransportException not retried during schema registration
       InfinispanRemoteManager.registerSchemaWithRetry() caught
       HotRodClientException but immediately re-threw any exception that
       was not an IllegalLifecycleStateException (line: "if
       (!isIllegalLifecycleStateException(e)) throw e").
       TransportException is a HotRodClientException subclass representing
       a transient connectivity failure; on the very first retry attempt
       it escaped the loop, task.run() returned false, and the method
       threw IllegalStateException("Failed to register schema after PT1M")
       without actually waiting.
    
       Fix: add isTransportException() and treat TransportException as a
       retriable condition alongside IllegalLifecycleStateException.  This
       is also correct in production: if the server is briefly unreachable
       at startup (e.g. Kubernetes rolling deploy), schema registration
       should retry within the configured timeout rather than fail
       immediately.
    
       Additionally, waitForCacheReady() in InfinispanRemoteTestSupport
       only ignored RemoteIllegalLifecycleStateException; it now also
       ignores TransportException so that transient startup races do not
       immediately fail the Awaitility condition.
    
    Co-authored-by: IBM Bob 2.2.1
    Signed-off-by: AurĂ©lien Pupier <[email protected]>
---
 .../infinispan/remote/InfinispanRemoteManager.java |  6 ++++-
 .../remote/InfinispanRemoteConfigurationIT.java    |  5 +++-
 .../remote/InfinispanRemoteEmbeddingStoreIT.java   |  4 ++-
 .../InfinispanRemoteKeyValueRepositoryIT.java      | 16 +++++++-----
 .../remote/InfinispanRemoteTestSupport.java        | 30 +++++++++++++++-------
 .../InfinispanRemoteClusteredTestSupport.java      |  4 ++-
 ...ispanRemoteIdempotentRepositoryTestSupport.java | 13 ++++++++--
 7 files changed, 56 insertions(+), 22 deletions(-)

diff --git 
a/components/camel-infinispan/camel-infinispan/src/main/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteManager.java
 
b/components/camel-infinispan/camel-infinispan/src/main/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteManager.java
index 092ce4e7f6f3..67c7d55440f8 100644
--- 
a/components/camel-infinispan/camel-infinispan/src/main/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteManager.java
+++ 
b/components/camel-infinispan/camel-infinispan/src/main/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteManager.java
@@ -167,7 +167,7 @@ public class InfinispanRemoteManager extends ServiceSupport 
implements Infinispa
                     EmbeddingStoreUtil.registerSchema(configuration, 
cacheContainer);
                     return true;
                 } catch (HotRodClientException e) {
-                    if (!isIllegalLifecycleStateException(e)) {
+                    if (!isIllegalLifecycleStateException(e) && 
!isTransportException(e)) {
                         throw e;
                     }
                     if (firstAttempt[0]) {
@@ -191,6 +191,10 @@ public class InfinispanRemoteManager extends 
ServiceSupport implements Infinispa
         }
     }
 
+    private static boolean isTransportException(HotRodClientException e) {
+        return e.getClass().getSimpleName().contains("TransportException");
+    }
+
     private static boolean 
isIllegalLifecycleStateException(HotRodClientException e) {
         if 
(e.getClass().getSimpleName().contains("IllegalLifecycleStateException")) {
             return true;
diff --git 
a/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteConfigurationIT.java
 
b/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteConfigurationIT.java
index a446e5ce95d6..39fb9e4477fb 100644
--- 
a/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteConfigurationIT.java
+++ 
b/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteConfigurationIT.java
@@ -66,7 +66,10 @@ public class InfinispanRemoteConfigurationIT {
         cacheContConf.put("connection_timeout", "15000");
         configuration.setConfigurationProperties(cacheContConf);
 
-        configuration.setHosts(service.host() + ":" + service.port());
+        // Normalise "localhost" to "127.0.0.1" so the JVM does not resolve it 
to ::1 (IPv6),
+        // which the server does not bind to in host-network mode on 
Podman/Linux.
+        String host = InfinispanRemoteTestSupport.resolvedHost(service.host());
+        configuration.setHosts(host + ":" + service.port());
         configuration.setSecure(true);
         configuration.setUsername(service.username());
         configuration.setPassword(service.password());
diff --git 
a/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteEmbeddingStoreIT.java
 
b/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteEmbeddingStoreIT.java
index 913f16234a31..6bea22160325 100644
--- 
a/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteEmbeddingStoreIT.java
+++ 
b/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteEmbeddingStoreIT.java
@@ -188,7 +188,9 @@ public class InfinispanRemoteEmbeddingStoreIT extends 
InfinispanRemoteTestSuppor
 
     private InfinispanRemoteConfiguration 
createInfinispanRemoteConfiguration() {
         InfinispanRemoteConfiguration configuration = new 
InfinispanRemoteConfiguration();
-        configuration.setHosts(service.getServiceAddress());
+        // Normalise "localhost" to "127.0.0.1" so the JVM does not resolve it 
to ::1 (IPv6),
+        // which the server does not bind to in host-network mode on 
Podman/Linux.
+        
configuration.setHosts(InfinispanRemoteTestSupport.resolvedHost(service.host()) 
+ ":" + service.port());
         configuration.setUsername(service.username());
         configuration.setPassword(service.password());
         configuration.setSaslMechanism("SCRAM-SHA-512");
diff --git 
a/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteKeyValueRepositoryIT.java
 
b/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteKeyValueRepositoryIT.java
index 64cafe5a80f3..3b0660a89a82 100644
--- 
a/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteKeyValueRepositoryIT.java
+++ 
b/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteKeyValueRepositoryIT.java
@@ -23,7 +23,6 @@ import java.util.concurrent.TimeUnit;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.impl.DefaultCamelContext;
-import org.apache.camel.test.infra.infinispan.common.InfinispanProperties;
 import org.apache.camel.test.infra.infinispan.services.InfinispanService;
 import 
org.apache.camel.test.infra.infinispan.services.InfinispanServiceFactory;
 import org.infinispan.client.hotrod.RemoteCacheManager;
@@ -282,9 +281,11 @@ class InfinispanRemoteKeyValueRepositoryIT {
 
         clientBuilder.forceReturnValues(true);
 
+        // Normalise "localhost" to "127.0.0.1" so the JVM does not resolve it 
to ::1 (IPv6),
+        // which the server does not bind to in host-network mode on 
Podman/Linux.
         clientBuilder
                 .addServer()
-                .host(service.host())
+                .host("localhost".equalsIgnoreCase(service.host()) ? 
"127.0.0.1" : service.host())
                 .port(service.port());
 
         clientBuilder
@@ -298,11 +299,12 @@ class InfinispanRemoteKeyValueRepositoryIT {
                 .saslMechanism("SCRAM-SHA-512")
                 .realm("default");
 
-        if 
(!Boolean.getBoolean(InfinispanProperties.INFINISPAN_CONTAINER_NETWORK_MODE_HOST))
 {
-            Properties properties = new Properties();
-            properties.put("infinispan.client.hotrod.client_intelligence", 
"BASIC");
-            clientBuilder.withProperties(properties);
-        }
+        // Always use BASIC intelligence to prevent the client from following 
server topology
+        // and reconnecting to an address that may resolve to IPv6 (::1) on 
Podman/Linux,
+        // where the Infinispan server only listens on IPv4.
+        Properties properties = new Properties();
+        properties.put("infinispan.client.hotrod.client_intelligence", 
"BASIC");
+        clientBuilder.withProperties(properties);
         return clientBuilder;
     }
 }
diff --git 
a/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteTestSupport.java
 
b/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteTestSupport.java
index 347fce543e68..5e4aa8f61e9e 100644
--- 
a/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteTestSupport.java
+++ 
b/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteTestSupport.java
@@ -26,13 +26,13 @@ import org.apache.camel.support.task.ForegroundTask;
 import org.apache.camel.support.task.Tasks;
 import org.apache.camel.support.task.budget.Budgets;
 import org.apache.camel.support.task.budget.IterationBoundedBudget;
-import org.apache.camel.test.infra.infinispan.common.InfinispanProperties;
 import org.apache.camel.test.infra.infinispan.services.InfinispanService;
 import 
org.apache.camel.test.infra.infinispan.services.InfinispanServiceFactory;
 import org.awaitility.Awaitility;
 import org.infinispan.client.hotrod.RemoteCacheManager;
 import org.infinispan.client.hotrod.configuration.ConfigurationBuilder;
 import 
org.infinispan.client.hotrod.exceptions.RemoteIllegalLifecycleStateException;
+import org.infinispan.client.hotrod.exceptions.TransportException;
 import org.infinispan.commons.api.BasicCache;
 import org.infinispan.configuration.cache.CacheMode;
 import org.junit.jupiter.api.Assumptions;
@@ -113,10 +113,11 @@ public class InfinispanRemoteTestSupport extends 
InfinispanTestSupport {
         clientBuilder
                 .forceReturnValues(true);
 
-        // add server from the test infra service
+        // add server from the test infra service; normalise "localhost" to 
"127.0.0.1" so the
+        // JVM does not resolve it to the IPv6 loopback (::1), which the 
server does not bind to.
         clientBuilder
                 .addServer()
-                .host(service.host())
+                .host(resolvedHost(service.host()))
                 .port(service.port());
 
         // add security info
@@ -131,14 +132,24 @@ public class InfinispanRemoteTestSupport extends 
InfinispanTestSupport {
                 .saslMechanism("SCRAM-SHA-512")
                 .realm("default");
 
-        if 
(!Boolean.getBoolean(InfinispanProperties.INFINISPAN_CONTAINER_NETWORK_MODE_HOST))
 {
-            Properties properties = new Properties();
-            properties.put("infinispan.client.hotrod.client_intelligence", 
"BASIC");
-            clientBuilder.withProperties(properties);
-        }
+        // Always use BASIC intelligence to prevent the client from following 
server topology
+        // and reconnecting to an address that may resolve to IPv6 (::1) on 
Podman/Linux,
+        // where the Infinispan server only listens on IPv4.
+        Properties properties = new Properties();
+        properties.put("infinispan.client.hotrod.client_intelligence", 
"BASIC");
+        clientBuilder.withProperties(properties);
         return clientBuilder;
     }
 
+    /**
+     * Normalises a hostname so that {@code "localhost"} is always returned as 
{@code "127.0.0.1"}. On Linux with Podman
+     * the JVM resolves {@code "localhost"} to the IPv6 loopback ({@code ::1}) 
before the IPv4 one, but the Infinispan
+     * server only listens on IPv4 in host-network mode.
+     */
+    public static String resolvedHost(String host) {
+        return "localhost".equalsIgnoreCase(host) ? "127.0.0.1" : host;
+    }
+
     @BindToRegistry
     public ComponentCustomizer infinispanComponentCustomizer() {
         return ComponentCustomizer.forType(
@@ -150,7 +161,8 @@ public class InfinispanRemoteTestSupport extends 
InfinispanTestSupport {
         Awaitility.await()
                 .atMost(Duration.ofMillis(timeoutMs))
                 .pollInterval(Duration.ofMillis(250))
-                .ignoreExceptionsMatching(e -> e instanceof 
RemoteIllegalLifecycleStateException)
+                .ignoreExceptionsMatching(
+                        e -> e instanceof RemoteIllegalLifecycleStateException 
|| e instanceof TransportException)
                 .until(() -> {
                     // Attempt to create/get the cache
                     manager.administration()
diff --git 
a/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/cluster/InfinispanRemoteClusteredTestSupport.java
 
b/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/cluster/InfinispanRemoteClusteredTestSupport.java
index 99bd7026d9a7..fa77ee376532 100644
--- 
a/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/cluster/InfinispanRemoteClusteredTestSupport.java
+++ 
b/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/cluster/InfinispanRemoteClusteredTestSupport.java
@@ -35,10 +35,12 @@ public final class InfinispanRemoteClusteredTestSupport {
 
         properties.put("infinispan.client.hotrod.client_intelligence", 
"BASIC");
 
+        // Normalise "localhost" to "127.0.0.1" so the JVM does not resolve it 
to ::1 (IPv6),
+        // which the server does not bind to in host-network mode on 
Podman/Linux.
         return new ConfigurationBuilder()
                 .withProperties(properties)
                 .addServer()
-                .host(service.host())
+                .host("localhost".equalsIgnoreCase(service.host()) ? 
"127.0.0.1" : service.host())
                 .port(service.port())
                 .security()
                 .authentication()
diff --git 
a/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/spring/SpringInfinispanRemoteIdempotentRepositoryTestSupport.java
 
b/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/spring/SpringInfinispanRemoteIdempotentRepositoryTestSupport.java
index 16b64f0efd67..edb5cf4320e2 100644
--- 
a/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/spring/SpringInfinispanRemoteIdempotentRepositoryTestSupport.java
+++ 
b/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/spring/SpringInfinispanRemoteIdempotentRepositoryTestSupport.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.infinispan.remote.spring;
 
+import java.util.Properties;
 import java.util.UUID;
 
 import 
org.apache.camel.component.infinispan.remote.InfinispanRemoteTestSupport;
@@ -46,10 +47,11 @@ public abstract class 
SpringInfinispanRemoteIdempotentRepositoryTestSupport exte
         clientBuilder
                 .forceReturnValues(true);
 
-        // add server from the test infra service
+        // add server from the test infra service; normalise "localhost" to 
"127.0.0.1" so the
+        // JVM does not resolve it to the IPv6 loopback (::1), which the 
server does not bind to.
         clientBuilder
                 .addServer()
-                .host(service.host())
+                .host(InfinispanRemoteTestSupport.resolvedHost(service.host()))
                 .port(service.port());
 
         // add security info
@@ -64,6 +66,13 @@ public abstract class 
SpringInfinispanRemoteIdempotentRepositoryTestSupport exte
                 .saslMechanism("SCRAM-SHA-512")
                 .realm("default");
 
+        // Always use BASIC intelligence to prevent the client from following 
server topology
+        // and reconnecting to an address that may resolve to IPv6 (::1) on 
Podman/Linux,
+        // where the Infinispan server only listens on IPv4.
+        Properties intelligenceProps = new Properties();
+        intelligenceProps.put("infinispan.client.hotrod.client_intelligence", 
"BASIC");
+        clientBuilder.withProperties(intelligenceProps);
+
         RemoteCacheManager manager = new 
RemoteCacheManager(clientBuilder.create());
         
MarshallerRegistration.init(MarshallerUtil.getSerializationContext(manager));
         InfinispanRemoteTestSupport.waitForCacheReady(manager, "idempotent", 
30000);

Reply via email to