From 7e7bedb3572ef27c0024b1cb2689dafa0a71cb8a Mon Sep 17 00:00:00 2001 From: Pascal Zimmermann Date: Sat, 31 Oct 2026 10:34:53 +0100 Subject: [PATCH 1/2] feat: Simplify reservable port setup for the default router group Reuse the shared RoutingClient instead of building a second one, drop the Mono bean with initMethod = "block", and stop making the cleaner depend on it. Fail with a clear message if there is no default-tcp router group. --- .../IntegrationTestConfiguration.java | 85 ++++++++----------- 1 file changed, 37 insertions(+), 48 deletions(-) diff --git a/integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java b/integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java index e214b2b6b5..467723f786 100644 --- a/integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java +++ b/integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java @@ -76,6 +76,7 @@ import org.cloudfoundry.routing.RoutingClient; import org.cloudfoundry.routing.v1.routergroups.ListRouterGroupsRequest; import org.cloudfoundry.routing.v1.routergroups.ListRouterGroupsResponse; +import org.cloudfoundry.routing.v1.routergroups.RouterGroup; import org.cloudfoundry.routing.v1.routergroups.UpdateRouterGroupRequest; import org.cloudfoundry.uaa.UaaClient; import org.cloudfoundry.uaa.clients.CreateClientRequest; @@ -94,10 +95,12 @@ import org.cloudfoundry.util.ResourceUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -257,7 +260,6 @@ String clientSecret(NameFactory nameFactory) { } @Bean - @DependsOn("routerGroupPorts") CloudFoundryCleaner cloudFoundryCleaner( @Qualifier("admin") CloudFoundryClient cloudFoundryClient, NameFactory nameFactory, @@ -458,53 +460,40 @@ String planName(NameFactory nameFactory) { return nameFactory.getPlanName(); } - // Tests allocate TCP ports from NameFactory, so the default router group has to reserve them - // regardless of the order in which the tests run (or of the deployment's default range). - @Bean(initMethod = "block") - Mono routerGroupPorts( - ConnectionContext connectionContext, - @Value("${test.admin.password}") String password, - @Value("${test.admin.username}") String username, - @Value("${skip.tcp.routing.tests:false}") boolean skipTcpRouting) { - if (skipTcpRouting) { - return Mono.empty(); - } - - // Not the shared routingClient: its token provider depends on the cleaner, which depends on - // this bean - RoutingClient routingClient = - ReactorRoutingClient.builder() - .connectionContext(connectionContext) - .tokenProvider( - PasswordGrantTokenProvider.builder() - .password(password) - .username(username) - .build()) - .build(); - - return routingClient - .routerGroups() - .list(ListRouterGroupsRequest.builder().build()) - .flatMapIterable(ListRouterGroupsResponse::getRouterGroups) - .filter(group -> "default-tcp".equals(group.getName())) - .next() - .switchIfEmpty( - Mono.fromRunnable( - () -> - this.logger.warn( - "No default-tcp router group, TCP route tests will" - + " fail"))) - .flatMap( - group -> - routingClient - .routerGroups() - .update( - UpdateRouterGroupRequest.builder() - .reservablePorts( - RandomNameFactory.PORT_RANGE) - .routerGroupId(group.getRouterGroupId()) - .build())) - .then(); + // Ensure that the default-tcp router group reserves the ports the tests allocate from + // NameFactory, regardless of the deployment's default range. Runs once all singletons exist; + // ApplicationRunner is not an option, as the tests use a plain SpringJUnitConfig. + @Bean + @ConditionalOnExpression( + "!'true'.equalsIgnoreCase(systemEnvironment['SKIP_TCP_ROUTING_TESTS'])") + SmartInitializingSingleton routerGroupPorts(RoutingClient routingClient) { + return () -> { + ListRouterGroupsResponse response = + routingClient + .routerGroups() + .list(ListRouterGroupsRequest.builder().build()) + .block(); + RouterGroup defaultGroup = + response.getRouterGroups().stream() + .filter(group -> "default-tcp".equals(group.getName())) + .findFirst() + .orElseThrow( + () -> + new IllegalStateException( + "No default-tcp router group, TCP route tests" + + " will fail. Set" + + " SKIP_TCP_ROUTING_TESTS=true to skip" + + " TCP routing tests entirely.")); + + routingClient + .routerGroups() + .update( + UpdateRouterGroupRequest.builder() + .reservablePorts(RandomNameFactory.PORT_RANGE) + .routerGroupId(defaultGroup.getRouterGroupId()) + .build()) + .block(); + }; } @Bean From 66b5a6b6703b696cf9a3083b54bd486d5652e365 Mon Sep 17 00:00:00 2001 From: Pascal Zimmermann Date: Sat, 31 Oct 2026 22:56:34 +0100 Subject: [PATCH 2/2] feat: Simplify the default router group lookup Resolve the default-tcp group with flatMapIterable and blockFirst instead of blocking on the whole response, which also avoids an NPE when the response is empty. --- .../IntegrationTestConfiguration.java | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java b/integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java index 467723f786..0e45747382 100644 --- a/integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java +++ b/integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java @@ -468,22 +468,20 @@ String planName(NameFactory nameFactory) { "!'true'.equalsIgnoreCase(systemEnvironment['SKIP_TCP_ROUTING_TESTS'])") SmartInitializingSingleton routerGroupPorts(RoutingClient routingClient) { return () -> { - ListRouterGroupsResponse response = + RouterGroup defaultGroup = routingClient .routerGroups() .list(ListRouterGroupsRequest.builder().build()) - .block(); - RouterGroup defaultGroup = - response.getRouterGroups().stream() + .flatMapIterable(ListRouterGroupsResponse::getRouterGroups) .filter(group -> "default-tcp".equals(group.getName())) - .findFirst() - .orElseThrow( - () -> - new IllegalStateException( - "No default-tcp router group, TCP route tests" - + " will fail. Set" - + " SKIP_TCP_ROUTING_TESTS=true to skip" - + " TCP routing tests entirely.")); + .blockFirst(); + + if (defaultGroup == null) { + throw new IllegalStateException( + "No default-tcp router group, TCP route tests will fail. Set" + + " SKIP_TCP_ROUTING_TESTS=true to skip TCP routing tests" + + " entirely."); + } routingClient .routerGroups()