diff --git a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerAutoConfiguration.java b/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerAutoConfiguration.java index 8ea470fa0..287626600 100644 --- a/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerAutoConfiguration.java +++ b/spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerAutoConfiguration.java @@ -162,14 +162,14 @@ List> endpointsSharedIndexInformers( @Bean @ConditionalOnMissingBean(value = V1Endpoints.class, parameterizedContainer = { List.class, Lister.class }) List> endpointsListers(List selectiveNamespaces, - List> serviceSharedIndexInformers) { + List> endpointsSharedIndexInformers) { int howManyNamespaces = selectiveNamespaces.size(); List> endpointsListers = new ArrayList<>(howManyNamespaces); for (int i = 0; i < howManyNamespaces; ++i) { String namespace = selectiveNamespaces.get(i); - Lister lister = new Lister<>(serviceSharedIndexInformers.get(i).getIndexer()); + Lister lister = new Lister<>(endpointsSharedIndexInformers.get(i).getIndexer()); LOG.debug(() -> "registering lister (for endpoints) in namespace : " + namespace); endpointsListers.add(lister); } diff --git a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerDiscoveryClientAutoConfigurationApplicationContextTests.java b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerDiscoveryClientAutoConfigurationApplicationContextTests.java index d9a1e7b8a..855f84f2b 100644 --- a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerDiscoveryClientAutoConfigurationApplicationContextTests.java +++ b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerDiscoveryClientAutoConfigurationApplicationContextTests.java @@ -16,13 +16,14 @@ package org.springframework.cloud.kubernetes.client.discovery; -import java.io.StringReader; +import java.util.List; +import com.github.tomakehurst.wiremock.junit5.WireMockExtension; import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.util.Config; -import org.junit.jupiter.api.AfterAll; +import io.kubernetes.client.util.ClientBuilder; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; -import org.testcontainers.k3s.K3sContainer; +import org.junit.jupiter.api.extension.RegisterExtension; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.health.contributor.HealthIndicator; @@ -35,14 +36,15 @@ import org.springframework.cloud.kubernetes.commons.KubernetesCommonsAutoConfiguration; import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryClientHealthIndicatorInitializer; import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryPropertiesAutoConfiguration; -import org.springframework.cloud.kubernetes.integration.tests.commons.Commons; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.cloud.kubernetes.client.discovery.TestUtils.assertInformerBeansMissing; import static org.springframework.cloud.kubernetes.client.discovery.TestUtils.assertInformerBeansPresent; +import static org.springframework.cloud.kubernetes.client.discovery.TestUtils.mockEndpointsAndServices; /** * Test various conditionals for @@ -54,15 +56,21 @@ class KubernetesClientInformerDiscoveryClientAutoConfigurationApplicationContext private ApplicationContextRunner applicationContextRunner; - private static K3sContainer container; + @RegisterExtension + private static final WireMockExtension API_SERVER = WireMockExtension.newInstance() + .options(options().dynamicPort()) + .build(); - @AfterAll - static void afterAll() { - container.stop(); + @AfterEach + void afterEach() { + API_SERVER.resetAll(); } @Test void discoveryEnabledDefault() { + + mockEndpointsAndServices(List.of("default"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.kubernetes.client.namespace=default"); applicationContextRunner.run(context -> { @@ -82,6 +90,9 @@ void discoveryEnabledDefault() { @Test void discoveryEnabledDefaultWithSelectiveNamespaces() { + + mockEndpointsAndServices(List.of("a", "b", "c"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.kubernetes.discovery.namespaces=a,b,c"); applicationContextRunner.run(context -> { @@ -102,6 +113,9 @@ void discoveryEnabledDefaultWithSelectiveNamespaces() { @Test void discoveryEnabled() { + + mockEndpointsAndServices(List.of("default"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.enabled=true", "spring.cloud.kubernetes.client.namespace=default"); applicationContextRunner.run(context -> { @@ -121,6 +135,9 @@ void discoveryEnabled() { @Test void discoveryEnabledWithSelectiveNamespaces() { + + mockEndpointsAndServices(List.of("a", "b"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.enabled=true", "spring.cloud.kubernetes.discovery.namespaces=a,b"); applicationContextRunner.run(context -> { @@ -155,6 +172,7 @@ void discoveryDisabled() { @Test void discoveryDisabledWithSelectiveNamespaces() { + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.enabled=false", "spring.cloud.kubernetes.discovery.namespaces=a,b"); applicationContextRunner.run(context -> { @@ -185,6 +203,9 @@ void kubernetesDiscoveryEnabled() { @Test void kubernetesDiscoveryEnabledWithSelectiveNamespaces() { + + mockEndpointsAndServices(List.of("a", "b", "c", "d"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.kubernetes.discovery.enabled=true", "spring.cloud.kubernetes.discovery.namespaces=a,b,c,d"); @@ -239,6 +260,9 @@ void kubernetesDiscoveryDisabledWithSelectiveNamespaces() { @Test void kubernetesDiscoveryBlockingEnabled() { + + mockEndpointsAndServices(List.of("default"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.blocking.enabled=true", "spring.cloud.kubernetes.client.namespace=default"); applicationContextRunner.run(context -> { @@ -259,6 +283,9 @@ void kubernetesDiscoveryBlockingEnabled() { @Test void kubernetesDiscoveryBlockingEnabledWithSelectiveNamespaces() { + + mockEndpointsAndServices(List.of("a"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.blocking.enabled=true", "spring.cloud.kubernetes.discovery.namespaces=a"); applicationContextRunner.run(context -> { @@ -279,6 +306,9 @@ void kubernetesDiscoveryBlockingEnabledWithSelectiveNamespaces() { @Test void kubernetesDiscoveryBlockingDisabled() { + + mockEndpointsAndServices(List.of("default"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.blocking.enabled=false", "spring.cloud.kubernetes.client.namespace=default"); applicationContextRunner.run(context -> { @@ -298,6 +328,9 @@ void kubernetesDiscoveryBlockingDisabled() { @Test void kubernetesDiscoveryBlockingDisabledWithSelectiveNamespaces() { + + mockEndpointsAndServices(List.of("a", "b"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.blocking.enabled=false", "spring.cloud.kubernetes.discovery.namespaces=a,b"); applicationContextRunner.run(context -> { @@ -317,6 +350,9 @@ void kubernetesDiscoveryBlockingDisabledWithSelectiveNamespaces() { @Test void kubernetesDiscoveryHealthIndicatorEnabled() { + + mockEndpointsAndServices(List.of("default"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.client.health-indicator.enabled=true", "spring.cloud.kubernetes.client.namespace=default"); @@ -337,6 +373,9 @@ void kubernetesDiscoveryHealthIndicatorEnabled() { @Test void kubernetesDiscoveryHealthIndicatorEnabledWithSelectiveNamespaces() { + + mockEndpointsAndServices(List.of("b"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.client.health-indicator.enabled=true", "spring.cloud.kubernetes.discovery.namespaces=b"); @@ -357,6 +396,9 @@ void kubernetesDiscoveryHealthIndicatorEnabledWithSelectiveNamespaces() { @Test void kubernetesDiscoveryHealthIndicatorDisabled() { + + mockEndpointsAndServices(List.of("default"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.client.health-indicator.enabled=false", "spring.cloud.kubernetes.client.namespace=default"); @@ -373,6 +415,9 @@ void kubernetesDiscoveryHealthIndicatorDisabled() { @Test void kubernetesDiscoveryHealthIndicatorDisabledWithSelectiveNamespaces() { + + mockEndpointsAndServices(List.of("b"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.client.health-indicator.enabled=false", "spring.cloud.kubernetes.discovery.namespaces=b"); @@ -389,6 +434,9 @@ void kubernetesDiscoveryHealthIndicatorDisabledWithSelectiveNamespaces() { @Test void kubernetesDiscoveryHealthIndicatorEnabledHealthIndicatorMissing() { + + mockEndpointsAndServices(List.of("default"), API_SERVER); + setupWithFilteredClassLoader(HealthIndicator.class, "spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.client.health-indicator.enabled=true", "spring.cloud.kubernetes.client.namespace=default"); @@ -411,6 +459,9 @@ void kubernetesDiscoveryHealthIndicatorEnabledHealthIndicatorMissing() { @Test void kubernetesDiscoveryHealthIndicatorEnabledHealthIndicatorMissingWithSelectiveNamespaces() { + + mockEndpointsAndServices(List.of("a", "b", "c", "d", "e"), API_SERVER); + setupWithFilteredClassLoader(HealthIndicator.class, "spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.client.health-indicator.enabled=true", "spring.cloud.kubernetes.discovery.namespaces=a,b,c,d,e"); @@ -437,6 +488,9 @@ void kubernetesDiscoveryHealthIndicatorEnabledHealthIndicatorMissingWithSelectiv */ @Test void kubernetesDiscoveryReactiveCacheableEnabledBlockingDisabled() { + + mockEndpointsAndServices(List.of("a", "b"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.blocking.enabled=false", "spring.cloud.kubernetes.discovery.cacheable.reactive.enabled=true", @@ -462,6 +516,9 @@ void kubernetesDiscoveryReactiveCacheableEnabledBlockingDisabled() { */ @Test void reactiveDisabled() { + + mockEndpointsAndServices(List.of("default"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.reactive.enabled=false", "spring.cloud.kubernetes.client.namespace=default"); applicationContextRunner.run(context -> { @@ -480,6 +537,9 @@ void reactiveDisabled() { */ @Test void reactiveDisabledWithSelectiveNamespaces() { + + mockEndpointsAndServices(List.of("a", "b", "c", "d", "e"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.reactive.enabled=false", "spring.cloud.kubernetes.discovery.namespaces=a,b,c,d,e"); @@ -503,6 +563,9 @@ void reactiveDisabledWithSelectiveNamespaces() { */ @Test void blockingCacheableDefault() { + + mockEndpointsAndServices(List.of("default"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.kubernetes.client.namespace=default"); applicationContextRunner.run(context -> { @@ -520,6 +583,9 @@ void blockingCacheableDefault() { */ @Test void blockingCacheableDisabled() { + + mockEndpointsAndServices(List.of("default"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.kubernetes.discovery.cacheable.blocking.enabled=false", "spring.cloud.kubernetes.client.namespace=default"); @@ -538,6 +604,9 @@ void blockingCacheableDisabled() { */ @Test void blockingCacheableEnabled() { + + mockEndpointsAndServices(List.of("default"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.kubernetes.discovery.cacheable.blocking.enabled=true", "spring.cloud.kubernetes.client.namespace=default"); @@ -585,10 +654,7 @@ static class ApiClientConfig { @Bean @Primary ApiClient apiClient() throws Exception { - container = Commons.container(); - container.start(); - - return Config.fromConfig(new StringReader(container.getKubeConfigYaml())); + return new ClientBuilder().setBasePath("http://localhost:" + API_SERVER.getPort()).build(); } } diff --git a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerReactiveDiscoveryClientAutoConfigurationApplicationContextTests.java b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerReactiveDiscoveryClientAutoConfigurationApplicationContextTests.java index c596c5b0d..f521d6abe 100644 --- a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerReactiveDiscoveryClientAutoConfigurationApplicationContextTests.java +++ b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerReactiveDiscoveryClientAutoConfigurationApplicationContextTests.java @@ -16,13 +16,14 @@ package org.springframework.cloud.kubernetes.client.discovery; -import java.io.StringReader; +import java.util.List; +import com.github.tomakehurst.wiremock.junit5.WireMockExtension; import io.kubernetes.client.openapi.ApiClient; -import io.kubernetes.client.util.Config; -import org.junit.jupiter.api.AfterAll; +import io.kubernetes.client.util.ClientBuilder; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; -import org.testcontainers.k3s.K3sContainer; +import org.junit.jupiter.api.extension.RegisterExtension; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.FilteredClassLoader; @@ -34,14 +35,15 @@ import org.springframework.cloud.kubernetes.commons.KubernetesCommonsAutoConfiguration; import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryClientHealthIndicatorInitializer; import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryPropertiesAutoConfiguration; -import org.springframework.cloud.kubernetes.integration.tests.commons.Commons; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.cloud.kubernetes.client.discovery.TestUtils.assertInformerBeansMissing; import static org.springframework.cloud.kubernetes.client.discovery.TestUtils.assertInformerBeansPresent; +import static org.springframework.cloud.kubernetes.client.discovery.TestUtils.mockEndpointsAndServices; /** * Test various conditionals for @@ -53,15 +55,21 @@ class KubernetesClientInformerReactiveDiscoveryClientAutoConfigurationApplicatio private ApplicationContextRunner applicationContextRunner; - private static K3sContainer container; + @RegisterExtension + private static final WireMockExtension API_SERVER = WireMockExtension.newInstance() + .options(options().dynamicPort()) + .build(); - @AfterAll - static void afterAll() { - container.stop(); + @AfterEach + void afterEach() { + API_SERVER.resetAll(); } @Test void discoveryEnabledDefault() { + + mockEndpointsAndServices(List.of("default"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.kubernetes.client.namespace=default"); applicationContextRunner.run(context -> { @@ -78,6 +86,9 @@ void discoveryEnabledDefault() { @Test void discoveryEnabledDefaultWithSelectiveNamespaces() { + + mockEndpointsAndServices(List.of("a", "b", "c"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.kubernetes.discovery.namespaces=a,b,c"); applicationContextRunner.run(context -> { @@ -94,6 +105,9 @@ void discoveryEnabledDefaultWithSelectiveNamespaces() { @Test void discoveryEnabled() { + + mockEndpointsAndServices(List.of("default"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.enabled=true", "spring.cloud.kubernetes.client.namespace=default"); applicationContextRunner.run(context -> { @@ -110,6 +124,9 @@ void discoveryEnabled() { @Test void discoveryEnabledWithSelectiveNamespaces() { + + mockEndpointsAndServices(List.of("a", "b", "c"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.enabled=true", "spring.cloud.kubernetes.discovery.namespaces=a,b,c"); applicationContextRunner.run(context -> { @@ -126,6 +143,7 @@ void discoveryEnabledWithSelectiveNamespaces() { @Test void discoveryDisabled() { + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.enabled=false"); applicationContextRunner.run(context -> { @@ -141,6 +159,9 @@ void discoveryDisabled() { @Test void discoveryDisabledWithSelectiveNamespaces() { + + mockEndpointsAndServices(List.of("a", "b", "c"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.enabled=false", "spring.cloud.kubernetes.discovery.namespaces=a,b,c"); applicationContextRunner.run(context -> { @@ -156,6 +177,9 @@ void discoveryDisabledWithSelectiveNamespaces() { @Test void kubernetesDiscoveryEnabled() { + + mockEndpointsAndServices(List.of("default"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.kubernetes.discovery.enabled=true", "spring.cloud.kubernetes.client.namespace=default"); applicationContextRunner.run(context -> { @@ -172,6 +196,9 @@ void kubernetesDiscoveryEnabled() { @Test void kubernetesDiscoveryEnabledWithSelectiveNamespaces() { + + mockEndpointsAndServices(List.of("a", "b"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.kubernetes.discovery.enabled=true", "spring.cloud.kubernetes.discovery.namespaces=a,b"); applicationContextRunner.run(context -> { @@ -204,6 +231,9 @@ void kubernetesDiscoveryDisabled() { @Test void kubernetesDiscoveryDisabledWithSelectiveNamespaces() { + + mockEndpointsAndServices(List.of("a", "b"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.kubernetes.discovery.enabled=false", "spring.cloud.kubernetes.discovery.namespaces=a,b"); applicationContextRunner.run(context -> { @@ -221,6 +251,9 @@ void kubernetesDiscoveryDisabledWithSelectiveNamespaces() { @Test void kubernetesReactiveDiscoveryEnabled() { + + mockEndpointsAndServices(List.of("default"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.reactive.enabled=true", "spring.cloud.kubernetes.client.namespace=default"); applicationContextRunner.run(context -> { @@ -237,6 +270,9 @@ void kubernetesReactiveDiscoveryEnabled() { @Test void kubernetesReactiveDiscoveryEnabledWithSelectiveNamespaces() { + + mockEndpointsAndServices(List.of("a", "b"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.reactive.enabled=true", "spring.cloud.kubernetes.discovery.namespaces=a,b"); applicationContextRunner.run(context -> { @@ -253,6 +289,9 @@ void kubernetesReactiveDiscoveryEnabledWithSelectiveNamespaces() { @Test void kubernetesReactiveDiscoveryDisabled() { + + mockEndpointsAndServices(List.of("default"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.reactive.enabled=false", "spring.cloud.kubernetes.client.namespace=default"); applicationContextRunner.run(context -> { @@ -268,6 +307,9 @@ void kubernetesReactiveDiscoveryDisabled() { @Test void kubernetesReactiveDiscoveryDisabledWithSelectiveNamespaces() { + + mockEndpointsAndServices(List.of("a", "b"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.reactive.enabled=false", "spring.cloud.kubernetes.discovery.namespaces=a,b"); applicationContextRunner.run(context -> { @@ -286,6 +328,9 @@ void kubernetesReactiveDiscoveryDisabledWithSelectiveNamespaces() { */ @Test void blockingDisabled() { + + mockEndpointsAndServices(List.of("default"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.blocking.enabled=false", "spring.cloud.kubernetes.client.namespace=default"); applicationContextRunner.run(context -> { @@ -305,6 +350,9 @@ void blockingDisabled() { */ @Test void blockingDisabledWithSelectiveNamespaces() { + + mockEndpointsAndServices(List.of("a", "b"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.blocking.enabled=false", "spring.cloud.kubernetes.discovery.namespaces=a,b"); applicationContextRunner.run(context -> { @@ -322,6 +370,9 @@ void blockingDisabledWithSelectiveNamespaces() { @Test void healthDisabled() { + + mockEndpointsAndServices(List.of("default"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.client.health-indicator.enabled=false", "spring.cloud.kubernetes.client.namespace=default"); @@ -338,6 +389,9 @@ void healthDisabled() { @Test void healthDisabledWithSelectiveNamespaces() { + + mockEndpointsAndServices(List.of("a", "b"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.client.health-indicator.enabled=false", "spring.cloud.kubernetes.discovery.namespaces=a,b"); @@ -354,6 +408,9 @@ void healthDisabledWithSelectiveNamespaces() { @Test void healthEnabledClassNotPresent() { + + mockEndpointsAndServices(List.of("default"), API_SERVER); + setupWithFilteredClassLoader("org.springframework.boot.health.contributor.ReactiveHealthIndicator", "spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.client.health-indicator.enabled=false", @@ -371,6 +428,9 @@ void healthEnabledClassNotPresent() { @Test void healthEnabledClassNotPresentWithSelectiveNamespaces() { + + mockEndpointsAndServices(List.of("a", "b"), API_SERVER); + setupWithFilteredClassLoader("org.springframework.boot.health.contributor.ReactiveHealthIndicator", "spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.discovery.client.health-indicator.enabled=false", @@ -395,6 +455,9 @@ void healthEnabledClassNotPresentWithSelectiveNamespaces() { */ @Test void reactiveCacheableDefault() { + + mockEndpointsAndServices(List.of("default"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.kubernetes.client.namespace=default"); applicationContextRunner.run(context -> { @@ -412,6 +475,9 @@ void reactiveCacheableDefault() { */ @Test void reactiveCacheableDisabled() { + + mockEndpointsAndServices(List.of("default"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.kubernetes.discovery.cacheable.reactive.enabled=false", "spring.cloud.kubernetes.client.namespace=default"); @@ -431,6 +497,9 @@ void reactiveCacheableDisabled() { */ @Test void reactiveCacheableEnabledWithoutHealthIndicator() { + + mockEndpointsAndServices(List.of("default"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.kubernetes.discovery.cacheable.reactive.enabled=true", "spring.cloud.discovery.client.health-indicator.enabled=false", @@ -451,6 +520,9 @@ void reactiveCacheableEnabledWithoutHealthIndicator() { */ @Test void reactiveCacheableEnabledWithHealthIndicator() { + + mockEndpointsAndServices(List.of("default"), API_SERVER); + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", "spring.cloud.kubernetes.discovery.cacheable.reactive.enabled=true", "spring.cloud.discovery.client.health-indicator.enabled=true", @@ -497,10 +569,7 @@ static class ApiClientConfig { @Bean @Primary ApiClient apiClient() throws Exception { - container = Commons.container(); - container.start(); - - return Config.fromConfig(new StringReader(container.getKubeConfigYaml())); + return new ClientBuilder().setBasePath("http://localhost:" + API_SERVER.getPort()).build(); } } diff --git a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/TestUtils.java b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/TestUtils.java index 4bde1419f..249f95b5d 100644 --- a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/TestUtils.java +++ b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/TestUtils.java @@ -18,16 +18,26 @@ import java.util.List; +import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.junit5.WireMockExtension; import io.kubernetes.client.informer.SharedIndexInformer; import io.kubernetes.client.informer.SharedInformerFactory; import io.kubernetes.client.informer.cache.Lister; +import io.kubernetes.client.openapi.JSON; import io.kubernetes.client.openapi.models.V1Endpoints; +import io.kubernetes.client.openapi.models.V1EndpointsList; +import io.kubernetes.client.openapi.models.V1ListMeta; +import io.kubernetes.client.openapi.models.V1ObjectMeta; import io.kubernetes.client.openapi.models.V1Service; +import io.kubernetes.client.openapi.models.V1ServiceList; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.ResolvableType; +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; import static org.assertj.core.api.Assertions.assertThat; /** @@ -105,4 +115,43 @@ static void assertInformerBeansMissing(AssertableApplicationContext context) { assertThat(endpointsListersBeanName).isEmpty(); } + static void mockEndpointsAndServices(List namespaces, WireMockExtension server) { + namespaces.forEach(namespace -> { + mockEndpointsCall(namespace, server); + mockServicesCall(namespace, server); + }); + } + + private static void mockEndpointsCall(String namespace, WireMockExtension server) { + + // watch=false, first call to populate watcher cache + server.stubFor(WireMock.get(urlMatching("^/api/v1/namespaces/" + namespace + "/endpoints.*")) + .withQueryParam("watch", equalTo("false")) + .willReturn(WireMock.aResponse() + .withStatus(200) + .withBody(JSON.serialize(new V1EndpointsList().metadata(new V1ListMeta().resourceVersion("0")) + .addItemsItem(new V1Endpoints().metadata(new V1ObjectMeta().namespace(namespace))))))); + + // watch=true, call to re-sync + server.stubFor(WireMock.get(urlMatching("^/api/v1/namespaces/" + namespace + "/endpoints.*")) + .withQueryParam("watch", WireMock.equalTo("true")) + .willReturn(aResponse().withStatus(200).withBody(""))); + } + + private static void mockServicesCall(String namespace, WireMockExtension server) { + + // watch=false, first call to populate watcher cache + server.stubFor(WireMock.get(urlMatching("^/api/v1/namespaces/" + namespace + "/services.*")) + .withQueryParam("watch", equalTo("false")) + .willReturn(WireMock.aResponse() + .withStatus(200) + .withBody(JSON.serialize(new V1ServiceList().metadata(new V1ListMeta().resourceVersion("0")) + .addItemsItem(new V1Service().metadata(new V1ObjectMeta().namespace(namespace))))))); + + // watch=true, call to re-sync + server.stubFor(WireMock.get(urlMatching("^/api/v1/namespaces/" + namespace + "/services.*")) + .withQueryParam("watch", equalTo("true")) + .willReturn(aResponse().withStatus(200).withBody(""))); + } + }