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 a7c1ba959f..cd28e03862 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 @@ -113,10 +113,10 @@ SharedIndexInformer servicesSharedIndexInformer(SharedInformerFactory SharedIndexInformer endpointsSharedIndexInformer(SharedInformerFactory sharedInformerFactory, ApiClient apiClient, String kubernetesClientNamespace) { - GenericKubernetesApi servicesApi = new GenericKubernetesApi<>(V1Endpoints.class, + GenericKubernetesApi endpointsApi = new GenericKubernetesApi<>(V1Endpoints.class, V1EndpointsList.class, "", "v1", "endpoints", apiClient); - return sharedInformerFactory.sharedIndexInformerFor(servicesApi, V1Endpoints.class, 0L, + return sharedInformerFactory.sharedIndexInformerFor(endpointsApi, V1Endpoints.class, 0L, kubernetesClientNamespace); } 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 4a3ce1920e..f616a0592b 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 @@ -17,11 +17,32 @@ package org.springframework.cloud.kubernetes.client.discovery; import java.io.StringReader; - +import java.util.Collections; +import java.util.concurrent.Semaphore; + +import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.extension.Parameters; +import com.github.tomakehurst.wiremock.extension.PostServeAction; +import com.github.tomakehurst.wiremock.extension.ServeEventListener; +import com.github.tomakehurst.wiremock.junit5.WireMockExtension; +import com.github.tomakehurst.wiremock.stubbing.ServeEvent; import io.kubernetes.client.openapi.ApiClient; +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.V1Pod; +import io.kubernetes.client.openapi.models.V1PodList; +import io.kubernetes.client.openapi.models.V1Service; +import io.kubernetes.client.openapi.models.V1ServiceList; +import io.kubernetes.client.util.ClientBuilder; import io.kubernetes.client.util.Config; import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; import org.testcontainers.k3s.K3sContainer; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -39,6 +60,9 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +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.assertNonSelectiveNamespacesBeansMissing; import static org.springframework.cloud.kubernetes.client.discovery.TestUtils.assertNonSelectiveNamespacesBeansPresent; @@ -53,271 +77,29 @@ */ class KubernetesClientInformerReactiveDiscoveryClientAutoConfigurationApplicationContextTests { - private ApplicationContextRunner applicationContextRunner; - - private static K3sContainer container; - - @AfterAll - static void afterAll() { - container.stop(); - } - - @Test - void discoveryEnabledDefault() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); - assertThat(context).hasBean("kubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); - - // simple from commons and ours - assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).hasSize(2); - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).hasBean("reactiveIndicatorInitializer"); - - assertNonSelectiveNamespacesBeansPresent(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void discoveryEnabledDefaultWithSelectiveNamespaces() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.kubernetes.discovery.namespaces=a,b,c"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); - assertThat(context).hasBean("selectiveNamespacesKubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); - - // simple from commons and ours - assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).hasSize(2); - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).hasBean("reactiveIndicatorInitializer"); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 3); - }); - } - - @Test - void discoveryEnabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.enabled=true"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); - assertThat(context).hasBean("kubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); - - // simple from commons and ours - assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).hasSize(2); - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).hasBean("reactiveIndicatorInitializer"); - - assertNonSelectiveNamespacesBeansPresent(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void discoveryEnabledWithSelectiveNamespaces() { - 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 -> { - assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); - assertThat(context).hasBean("selectiveNamespacesKubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); - - // simple from commons and ours - assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).hasSize(2); - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).hasBean("reactiveIndicatorInitializer"); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 3); - }); - } - - @Test - void discoveryDisabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.enabled=false"); - applicationContextRunner.run(context -> { - assertThat(context).doesNotHaveBean(KubernetesClientInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesClientInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @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,c"); - applicationContextRunner.run(context -> { - assertThat(context).doesNotHaveBean(KubernetesClientInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesClientInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void kubernetesDiscoveryEnabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.kubernetes.discovery.enabled=true"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); - assertThat(context).hasBean("kubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); - - // simple from commons and ours - assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).hasSize(2); - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).hasBean("reactiveIndicatorInitializer"); - - assertNonSelectiveNamespacesBeansPresent(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void kubernetesDiscoveryEnabledWithSelectiveNamespaces() { - 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 -> { - assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); - assertThat(context).hasBean("selectiveNamespacesKubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); - - // simple from commons and ours - assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).hasSize(2); - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).hasBean("reactiveIndicatorInitializer"); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 2); - }); - } - - @Test - void kubernetesDiscoveryDisabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.kubernetes.discovery.enabled=false"); - applicationContextRunner.run(context -> { - assertThat(context).doesNotHaveBean(KubernetesClientInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesClientInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - // only "simple" one from commons, as ours is not picked up - assertThat(context).hasSingleBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void kubernetesDiscoveryDisabledWithSelectiveNamespaces() { - 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 -> { - assertThat(context).doesNotHaveBean(KubernetesClientInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesClientInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - // only "simple" one from commons, as ours is not picked up - assertThat(context).hasSingleBean(ReactiveDiscoveryClientHealthIndicator.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void kubernetesReactiveDiscoveryEnabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.reactive.enabled=true"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); - assertThat(context).hasBean("kubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); - - // simple from commons and ours - assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).hasSize(2); - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).hasBean("reactiveIndicatorInitializer"); - - assertNonSelectiveNamespacesBeansPresent(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void kubernetesReactiveDiscoveryEnabledWithSelectiveNamespaces() { - 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 -> { - assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); - assertThat(context).hasBean("selectiveNamespacesKubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); - - // simple from commons and ours - assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).hasSize(2); - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).hasBean("reactiveIndicatorInitializer"); + private static final Parameters GET_ENDPOINTS_PARAMETERS = new Parameters(); - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 2); - }); - } + private static final Semaphore GET_ENDPOINTS_SEMAPHORE = new Semaphore(1); - @Test - void kubernetesReactiveDiscoveryDisabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.reactive.enabled=false"); - applicationContextRunner.run(context -> { - assertThat(context).doesNotHaveBean(KubernetesClientInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesClientInformerReactiveDiscoveryClient.class); + private static final String GET_ENDPOINTS_PARAMETER_NAME = "get-endpoints"; - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); + @RegisterExtension + private static final WireMockExtension API_SERVER = + WireMockExtension.newInstance() + .options(options().dynamicPort().extensions(new PostServeExtension())) + .build(); - assertNonSelectiveNamespacesBeansPresent(context); - assertSelectiveNamespacesBeansMissing(context); - }); + @BeforeEach + void beforeAll() throws InterruptedException { + mockEndpointsCall(); + mockServicesCall(); } - @Test - void kubernetesReactiveDiscoveryDisabledWithSelectiveNamespaces() { - 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 -> { - assertThat(context).doesNotHaveBean(KubernetesClientInformerDiscoveryClient.class); - assertThat(context).doesNotHaveBean(KubernetesClientInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 2); - }); - } + private ApplicationContextRunner applicationContextRunner; - /** - * blocking is disabled, and it should not impact reactive in any way. - */ @Test - void blockingDisabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.blocking.enabled=false"); + void discoveryEnabledDefault() { + setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false"); applicationContextRunner.run(context -> { assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); assertThat(context).hasBean("kubernetesClientInformerDiscoveryClient"); @@ -333,99 +115,352 @@ void blockingDisabled() { }); } - /** - * blocking is disabled, and it should not impact reactive in any way. - */ - @Test - void blockingDisabledWithSelectiveNamespaces() { - 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 -> { - assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); - assertThat(context).hasBean("selectiveNamespacesKubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); - - // simple from commons and ours - assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).hasSize(2); - assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - assertThat(context).hasBean("reactiveIndicatorInitializer"); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 2); - }); - } - - @Test - void healthDisabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", - "spring.cloud.discovery.client.health-indicator.enabled=false"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); - assertThat(context).hasBean("kubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - - assertNonSelectiveNamespacesBeansPresent(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void healthDisabledWithSelectiveNamespaces() { - 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"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); - assertThat(context).hasBean("selectiveNamespacesKubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 2); - }); - } - - @Test - void healthEnabledClassNotPresent() { - 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"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); - assertThat(context).hasBean("kubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - - assertNonSelectiveNamespacesBeansPresent(context); - assertSelectiveNamespacesBeansMissing(context); - }); - } - - @Test - void healthEnabledClassNotPresentWithSelectiveNamespaces() { - 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", - "spring.cloud.kubernetes.discovery.namespaces=a,b"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); - assertThat(context).hasBean("selectiveNamespacesKubernetesClientInformerDiscoveryClient"); - assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); - - assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); - assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); - - assertNonSelectiveNamespacesBeansMissing(context); - assertSelectiveNamespacesBeansPresent(context, 2); - }); - } +// @Test +// void discoveryEnabledDefaultWithSelectiveNamespaces() { +// setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", +// "spring.cloud.kubernetes.discovery.namespaces=a,b,c"); +// applicationContextRunner.run(context -> { +// assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); +// assertThat(context).hasBean("selectiveNamespacesKubernetesClientInformerDiscoveryClient"); +// assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); +// +// // simple from commons and ours +// assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).hasSize(2); +// assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); +// assertThat(context).hasBean("reactiveIndicatorInitializer"); +// +// assertNonSelectiveNamespacesBeansMissing(context); +// assertSelectiveNamespacesBeansPresent(context, 3); +// }); +// } +// +// @Test +// void discoveryEnabled() { +// setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", +// "spring.cloud.discovery.enabled=true"); +// applicationContextRunner.run(context -> { +// assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); +// assertThat(context).hasBean("kubernetesClientInformerDiscoveryClient"); +// assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); +// +// // simple from commons and ours +// assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).hasSize(2); +// assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); +// assertThat(context).hasBean("reactiveIndicatorInitializer"); +// +// assertNonSelectiveNamespacesBeansPresent(context); +// assertSelectiveNamespacesBeansMissing(context); +// }); +// } +// +// @Test +// void discoveryEnabledWithSelectiveNamespaces() { +// 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 -> { +// assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); +// assertThat(context).hasBean("selectiveNamespacesKubernetesClientInformerDiscoveryClient"); +// assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); +// +// // simple from commons and ours +// assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).hasSize(2); +// assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); +// assertThat(context).hasBean("reactiveIndicatorInitializer"); +// +// assertNonSelectiveNamespacesBeansMissing(context); +// assertSelectiveNamespacesBeansPresent(context, 3); +// }); +// } +// +// @Test +// void discoveryDisabled() { +// setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", +// "spring.cloud.discovery.enabled=false"); +// applicationContextRunner.run(context -> { +// assertThat(context).doesNotHaveBean(KubernetesClientInformerDiscoveryClient.class); +// assertThat(context).doesNotHaveBean(KubernetesClientInformerReactiveDiscoveryClient.class); +// +// assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); +// assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); +// +// assertNonSelectiveNamespacesBeansMissing(context); +// assertSelectiveNamespacesBeansMissing(context); +// }); +// } +// +// @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,c"); +// applicationContextRunner.run(context -> { +// assertThat(context).doesNotHaveBean(KubernetesClientInformerDiscoveryClient.class); +// assertThat(context).doesNotHaveBean(KubernetesClientInformerReactiveDiscoveryClient.class); +// +// assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); +// assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); +// +// assertNonSelectiveNamespacesBeansMissing(context); +// assertSelectiveNamespacesBeansMissing(context); +// }); +// } +// +// @Test +// void kubernetesDiscoveryEnabled() { +// setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", +// "spring.cloud.kubernetes.discovery.enabled=true"); +// applicationContextRunner.run(context -> { +// assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); +// assertThat(context).hasBean("kubernetesClientInformerDiscoveryClient"); +// assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); +// +// // simple from commons and ours +// assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).hasSize(2); +// assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); +// assertThat(context).hasBean("reactiveIndicatorInitializer"); +// +// assertNonSelectiveNamespacesBeansPresent(context); +// assertSelectiveNamespacesBeansMissing(context); +// }); +// } +// +// @Test +// void kubernetesDiscoveryEnabledWithSelectiveNamespaces() { +// 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 -> { +// assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); +// assertThat(context).hasBean("selectiveNamespacesKubernetesClientInformerDiscoveryClient"); +// assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); +// +// // simple from commons and ours +// assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).hasSize(2); +// assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); +// assertThat(context).hasBean("reactiveIndicatorInitializer"); +// +// assertNonSelectiveNamespacesBeansMissing(context); +// assertSelectiveNamespacesBeansPresent(context, 2); +// }); +// } +// +// @Test +// void kubernetesDiscoveryDisabled() { +// setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", +// "spring.cloud.kubernetes.discovery.enabled=false"); +// applicationContextRunner.run(context -> { +// assertThat(context).doesNotHaveBean(KubernetesClientInformerDiscoveryClient.class); +// assertThat(context).doesNotHaveBean(KubernetesClientInformerReactiveDiscoveryClient.class); +// +// assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); +// // only "simple" one from commons, as ours is not picked up +// assertThat(context).hasSingleBean(ReactiveDiscoveryClientHealthIndicator.class); +// +// assertNonSelectiveNamespacesBeansMissing(context); +// assertSelectiveNamespacesBeansMissing(context); +// }); +// } +// +// @Test +// void kubernetesDiscoveryDisabledWithSelectiveNamespaces() { +// 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 -> { +// assertThat(context).doesNotHaveBean(KubernetesClientInformerDiscoveryClient.class); +// assertThat(context).doesNotHaveBean(KubernetesClientInformerReactiveDiscoveryClient.class); +// +// assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); +// // only "simple" one from commons, as ours is not picked up +// assertThat(context).hasSingleBean(ReactiveDiscoveryClientHealthIndicator.class); +// +// assertNonSelectiveNamespacesBeansMissing(context); +// assertSelectiveNamespacesBeansMissing(context); +// }); +// } +// +// @Test +// void kubernetesReactiveDiscoveryEnabled() { +// setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", +// "spring.cloud.discovery.reactive.enabled=true"); +// applicationContextRunner.run(context -> { +// assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); +// assertThat(context).hasBean("kubernetesClientInformerDiscoveryClient"); +// assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); +// +// // simple from commons and ours +// assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).hasSize(2); +// assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); +// assertThat(context).hasBean("reactiveIndicatorInitializer"); +// +// assertNonSelectiveNamespacesBeansPresent(context); +// assertSelectiveNamespacesBeansMissing(context); +// }); +// } +// +// @Test +// void kubernetesReactiveDiscoveryEnabledWithSelectiveNamespaces() { +// 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 -> { +// assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); +// assertThat(context).hasBean("selectiveNamespacesKubernetesClientInformerDiscoveryClient"); +// assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); +// +// // simple from commons and ours +// assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).hasSize(2); +// assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); +// assertThat(context).hasBean("reactiveIndicatorInitializer"); +// +// assertNonSelectiveNamespacesBeansMissing(context); +// assertSelectiveNamespacesBeansPresent(context, 2); +// }); +// } +// +// @Test +// void kubernetesReactiveDiscoveryDisabled() { +// setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", +// "spring.cloud.discovery.reactive.enabled=false"); +// applicationContextRunner.run(context -> { +// assertThat(context).doesNotHaveBean(KubernetesClientInformerDiscoveryClient.class); +// assertThat(context).doesNotHaveBean(KubernetesClientInformerReactiveDiscoveryClient.class); +// +// assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); +// assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); +// +// assertNonSelectiveNamespacesBeansPresent(context); +// assertSelectiveNamespacesBeansMissing(context); +// }); +// } +// +// @Test +// void kubernetesReactiveDiscoveryDisabledWithSelectiveNamespaces() { +// 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 -> { +// assertThat(context).doesNotHaveBean(KubernetesClientInformerDiscoveryClient.class); +// assertThat(context).doesNotHaveBean(KubernetesClientInformerReactiveDiscoveryClient.class); +// +// assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); +// assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); +// +// assertNonSelectiveNamespacesBeansMissing(context); +// assertSelectiveNamespacesBeansPresent(context, 2); +// }); +// } +// +// /** +// * blocking is disabled, and it should not impact reactive in any way. +// */ +// @Test +// void blockingDisabled() { +// setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", +// "spring.cloud.discovery.blocking.enabled=false"); +// applicationContextRunner.run(context -> { +// assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); +// assertThat(context).hasBean("kubernetesClientInformerDiscoveryClient"); +// assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); +// +// // simple from commons and ours +// assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).hasSize(2); +// assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); +// assertThat(context).hasBean("reactiveIndicatorInitializer"); +// +// assertNonSelectiveNamespacesBeansPresent(context); +// assertSelectiveNamespacesBeansMissing(context); +// }); +// } +// +// /** +// * blocking is disabled, and it should not impact reactive in any way. +// */ +// @Test +// void blockingDisabledWithSelectiveNamespaces() { +// 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 -> { +// assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); +// assertThat(context).hasBean("selectiveNamespacesKubernetesClientInformerDiscoveryClient"); +// assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); +// +// // simple from commons and ours +// assertThat(context).getBeans(ReactiveDiscoveryClientHealthIndicator.class).hasSize(2); +// assertThat(context).hasSingleBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); +// assertThat(context).hasBean("reactiveIndicatorInitializer"); +// +// assertNonSelectiveNamespacesBeansMissing(context); +// assertSelectiveNamespacesBeansPresent(context, 2); +// }); +// } +// +// @Test +// void healthDisabled() { +// setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.config.enabled=false", +// "spring.cloud.discovery.client.health-indicator.enabled=false"); +// applicationContextRunner.run(context -> { +// assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); +// assertThat(context).hasBean("kubernetesClientInformerDiscoveryClient"); +// assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); +// +// assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); +// assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); +// +// assertNonSelectiveNamespacesBeansPresent(context); +// assertSelectiveNamespacesBeansMissing(context); +// }); +// } +// +// @Test +// void healthDisabledWithSelectiveNamespaces() { +// 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"); +// applicationContextRunner.run(context -> { +// assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); +// assertThat(context).hasBean("selectiveNamespacesKubernetesClientInformerDiscoveryClient"); +// assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); +// +// assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); +// assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); +// +// assertNonSelectiveNamespacesBeansMissing(context); +// assertSelectiveNamespacesBeansPresent(context, 2); +// }); +// } +// +// @Test +// void healthEnabledClassNotPresent() { +// 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"); +// applicationContextRunner.run(context -> { +// assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); +// assertThat(context).hasBean("kubernetesClientInformerDiscoveryClient"); +// assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); +// +// assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); +// assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); +// +// assertNonSelectiveNamespacesBeansPresent(context); +// assertSelectiveNamespacesBeansMissing(context); +// }); +// } +// +// @Test +// void healthEnabledClassNotPresentWithSelectiveNamespaces() { +// 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", +// "spring.cloud.kubernetes.discovery.namespaces=a,b"); +// applicationContextRunner.run(context -> { +// assertThat(context).hasSingleBean(KubernetesClientInformerDiscoveryClient.class); +// assertThat(context).hasBean("selectiveNamespacesKubernetesClientInformerDiscoveryClient"); +// assertThat(context).hasSingleBean(KubernetesClientInformerReactiveDiscoveryClient.class); +// +// assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class); +// assertThat(context).doesNotHaveBean(KubernetesDiscoveryClientHealthIndicatorInitializer.class); +// +// assertNonSelectiveNamespacesBeansMissing(context); +// assertSelectiveNamespacesBeansPresent(context, 2); +// }); +// } private void setup(String... properties) { applicationContextRunner = new ApplicationContextRunner() @@ -449,7 +484,7 @@ private void setupWithFilteredClassLoader(String name, String... properties) { KubernetesClientInformerSelectiveNamespacesAutoConfiguration.class, KubernetesCommonsAutoConfiguration.class, KubernetesClientInformerAutoConfiguration.class, KubernetesClientDiscoveryClientSpelAutoConfiguration.class)) - .withUserConfiguration(ApiClientConfig.class) + //.withUserConfiguration(ApiClientConfig.class) .withClassLoader(new FilteredClassLoader(name)) .withPropertyValues(properties); } @@ -460,12 +495,74 @@ static class ApiClientConfig { @Bean @Primary ApiClient apiClient() throws Exception { - container = Commons.container(); - container.start(); + return new ClientBuilder().setBasePath("http://localhost:" + API_SERVER.getPort()).build(); + } + + } + + private static void mockEndpointsCall() { + + // watch=false, first call to populate watcher cache + API_SERVER.stubFor( + WireMock.get(WireMock.urlMatching("^/api/v1/namespaces/default/endpoints.*")) + .withQueryParam("watch", WireMock.equalTo("false")) + .willReturn( + WireMock.aResponse() + .withStatus(200) + .withBody( + JSON.serialize( + new V1EndpointsList() + .metadata(new V1ListMeta().resourceVersion("0")) + .addItemsItem(new V1Endpoints().metadata(new V1ObjectMeta().namespace("default"))) + )))); + + // watch=true, call to re-sync + API_SERVER.stubFor(WireMock.get(WireMock.urlMatching("^/api/v1/namespaces/default/endpoints.*")) + .withQueryParam("watch", WireMock.equalTo("true")) + .willReturn(aResponse().withStatus(200).withBody("{}"))); + } - return Config.fromConfig(new StringReader(container.getKubeConfigYaml())); + private static void mockServicesCall() throws InterruptedException { + + // watch=false, first call to populate watcher cache + API_SERVER.stubFor( + WireMock.get(WireMock.urlMatching("^/api/v1/namespaces/default/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("default"))) + )))); + + GET_ENDPOINTS_SEMAPHORE.acquire(1); + GET_ENDPOINTS_PARAMETERS.put(GET_ENDPOINTS_PARAMETER_NAME, GET_ENDPOINTS_SEMAPHORE); + // watch=true, call to re-sync + API_SERVER.stubFor( + WireMock.get(WireMock.urlMatching("^/api/v1/namespaces/default/services.*")) + .withPostServeAction("PostServeExtension", GET_ENDPOINTS_PARAMETERS) + .withQueryParam("watch", equalTo("true")) + .willReturn(aResponse().withStatus(200).withBody("{}"))); + } + + private static final class PostServeExtension implements ServeEventListener { + + @Override + public String getName() { + return "PostServeExtension"; } + @Override + public void afterMatch(ServeEvent serveEvent, Parameters parameters) { + Object getEndpointsSemaphore = parameters.get(GET_ENDPOINTS_PARAMETER_NAME); + if (getEndpointsSemaphore != null) { + Semaphore semaphore = (Semaphore) getEndpointsSemaphore; + semaphore.release(); + } + } } } diff --git a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerReactiveDiscoveryClientAutoConfigurationTests.java b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerReactiveDiscoveryClientAutoConfigurationTests.java index b54bde292c..0b32360050 100644 --- a/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerReactiveDiscoveryClientAutoConfigurationTests.java +++ b/spring-cloud-kubernetes-client-discovery/src/test/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerReactiveDiscoveryClientAutoConfigurationTests.java @@ -88,12 +88,12 @@ ApiClient apiClient() { WireMock.configureFor(wireMockServer.port()); stubFor(get("/api/v1/namespaces/test/endpoints?resourceVersion=0&watch=false") .willReturn(aResponse().withStatus(200) - .withBody(new JSON().serialize(new V1EndpointsListBuilder() + .withBody(JSON.serialize(new V1EndpointsListBuilder() .withMetadata(new V1ListMetaBuilder().withResourceVersion("0").build()) .build())))); stubFor(get("/api/v1/namespaces/test/services?resourceVersion=0&watch=false") .willReturn(aResponse().withStatus(200) - .withBody(new JSON().serialize(new V1ServiceListBuilder() + .withBody(JSON.serialize(new V1ServiceListBuilder() .withMetadata(new V1ListMetaBuilder().withResourceVersion("0").build()) .build())))); return new ClientBuilder().setBasePath(wireMockServer.baseUrl()).build();