diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/pom.xml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/pom.xml index decf9905f1..40653ab7c4 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/pom.xml +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/pom.xml @@ -11,6 +11,11 @@ spring-cloud-kubernetes-k8s-client-discovery-server + + true + true + + org.springframework.boot @@ -43,10 +48,6 @@ ../src/main/resources true - - src/main/resources - true - diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/main/java/org/springframework/cloud/kubernetes/discoveryclient/it/App.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/main/java/org/springframework/cloud/kubernetes/discoveryclient/it/App.java new file mode 100644 index 0000000000..7eb896a8a8 --- /dev/null +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/main/java/org/springframework/cloud/kubernetes/discoveryclient/it/App.java @@ -0,0 +1,34 @@ +/* + * Copyright 2013-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.kubernetes.discoveryclient.it; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; + +/** + * @author wind57 + */ +@SpringBootApplication +@EnableScheduling +public class App { + + public static void main(String[] args) { + SpringApplication.run(App.class, args); + } + +} diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/main/java/org/springframework/cloud/kubernetes/discoveryclient/it/HeartbeatListener.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/main/java/org/springframework/cloud/kubernetes/discoveryclient/it/HeartbeatListener.java index 099bd69bd9..846871a08c 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/main/java/org/springframework/cloud/kubernetes/discoveryclient/it/HeartbeatListener.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/main/java/org/springframework/cloud/kubernetes/discoveryclient/it/HeartbeatListener.java @@ -35,12 +35,12 @@ class HeartbeatListener implements ApplicationListener { private static final LogAccessor LOG = new LogAccessor(LogFactory.getLog(HeartbeatListener.class)); - AtomicReference> state = new AtomicReference<>(List.of()); + public final AtomicReference> state = new AtomicReference<>(List.of()); @Override @SuppressWarnings("unchecked") public void onApplicationEvent(HeartbeatEvent event) { - LOG.info("received heartbeat event"); + LOG.info("received heartbeat event in listener"); List state = (List) event.getValue(); this.state.set(state); LOG.info("state received : " + state); diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/main/java/org/springframework/cloud/kubernetes/discoveryclient/it/KubernetesDiscoveryClientApplicationIt.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/main/java/org/springframework/cloud/kubernetes/discoveryclient/it/KubernetesDiscoveryClientApplicationIt.java deleted file mode 100644 index 6f90bae995..0000000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/main/java/org/springframework/cloud/kubernetes/discoveryclient/it/KubernetesDiscoveryClientApplicationIt.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2013-2021 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.kubernetes.discoveryclient.it; - -import java.util.List; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.client.ServiceInstance; -import org.springframework.cloud.client.discovery.DiscoveryClient; -import org.springframework.cloud.kubernetes.commons.discovery.EndpointNameAndNamespace; -import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RestController; - -/** - * @author Ryan Baxter - */ -@SpringBootApplication -@EnableScheduling -@RestController -class KubernetesDiscoveryClientApplicationIt { - - private final DiscoveryClient discoveryClient; - - private final HeartbeatListener heartbeatListener; - - KubernetesDiscoveryClientApplicationIt(DiscoveryClient discoveryClient, HeartbeatListener heartbeatListener) { - this.discoveryClient = discoveryClient; - this.heartbeatListener = heartbeatListener; - } - - public static void main(String[] args) { - SpringApplication.run(KubernetesDiscoveryClientApplicationIt.class, args); - } - - @GetMapping("/services") - List services() { - return discoveryClient.getServices(); - } - - @GetMapping("/service/{serviceId}") - List service(@PathVariable String serviceId) { - return discoveryClient.getInstances(serviceId); - } - - @GetMapping("/state") - List state() { - return heartbeatListener.state.get(); - } - -} diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/main/resources/application.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/main/resources/application.yaml deleted file mode 100644 index ae3c741115..0000000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/main/resources/application.yaml +++ /dev/null @@ -1,17 +0,0 @@ -server: - servlet: - context-path: /discoveryclient-it - -spring: - cloud: - kubernetes: - discovery: - discoveryServerUrl: http://spring-cloud-kubernetes-discoveryserver -management: - endpoint: - health: - show-details: always - endpoints: - web: - exposure: - include: "*" diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/java/org/springframework/cloud/kubernetes/discoveryclient/it/DiscoveryClientFilterNamespaceDelegate.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/java/org/springframework/cloud/kubernetes/discoveryclient/it/DiscoveryClientFilterNamespaceDelegate.java deleted file mode 100644 index 2cb325e611..0000000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/java/org/springframework/cloud/kubernetes/discoveryclient/it/DiscoveryClientFilterNamespaceDelegate.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2013-2021 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.kubernetes.discoveryclient.it; - -import java.time.Duration; -import java.util.LinkedHashMap; -import java.util.Objects; - -import org.assertj.core.api.Assertions; -import org.assertj.core.api.Condition; -import org.testcontainers.k3s.K3sContainer; -import reactor.netty.http.client.HttpClient; -import reactor.util.retry.Retry; -import reactor.util.retry.RetryBackoffSpec; - -import org.springframework.boot.test.json.BasicJsonTester; -import org.springframework.cloud.kubernetes.integration.tests.commons.Commons; -import org.springframework.http.HttpMethod; -import org.springframework.http.client.reactive.ReactorClientHttpConnector; -import org.springframework.web.reactive.function.client.WebClient; - -/** - * @author mbialkowski1 - */ -final class DiscoveryClientFilterNamespaceDelegate { - - private DiscoveryClientFilterNamespaceDelegate() { - - } - - private static final BasicJsonTester BASIC_JSON_TESTER = new BasicJsonTester( - DiscoveryClientFilterNamespaceDelegate.class); - - static void testNamespaceDiscoveryClient(K3sContainer container) { - testLoadBalancer(); - testHealth(); - testForHeartbeat(container); - } - - private static void testLoadBalancer() { - - WebClient.Builder builder = builder(); - WebClient serviceClient = builder.baseUrl("http://localhost:80/discoveryclient-it/services").build(); - String result = serviceClient.method(HttpMethod.GET) - .retrieve() - .bodyToMono(String.class) - .retryWhen(retrySpec()) - .block(); - - Assertions.assertThat(BASIC_JSON_TESTER.from(result)) - .extractingJsonPathArrayValue("$") - .contains("service-wiremock"); - - // ServiceInstance - WebClient serviceInstanceClient = builder - .baseUrl("http://localhost:80/discoveryclient-it/service/service-wiremock") - .build(); - String serviceInstances = serviceInstanceClient.method(HttpMethod.GET) - .retrieve() - .bodyToMono(String.class) - .retryWhen(retrySpec()) - .block(); - - Assertions.assertThat(BASIC_JSON_TESTER.from(serviceInstances)) - .extractingJsonPathStringValue("$.[0].serviceId") - .isEqualTo("service-wiremock"); - - Assertions.assertThat(BASIC_JSON_TESTER.from(serviceInstances)) - .extractingJsonPathStringValue("$.[0].namespace") - .isEqualTo("left"); - } - - private static void testHealth() { - WebClient.Builder builder = builder(); - WebClient serviceClient = builder.baseUrl("http://localhost:80/discoveryclient-it/actuator/health").build(); - - String health = serviceClient.method(HttpMethod.GET) - .retrieve() - .bodyToMono(String.class) - .retryWhen(retrySpec()) - .block(); - - Assertions.assertThat(BASIC_JSON_TESTER.from(health)) - .extractingJsonPathStringValue("$.components.discoveryComposite.status") - .isEqualTo("UP"); - } - - private static void testForHeartbeat(K3sContainer container) { - - // 1. logs from discovery server - Commons.waitForLogStatement("using delay : 3000", container, "spring-cloud-kubernetes-discoveryserver"); - Commons.waitForLogStatement("received heartbeat event", container, "spring-cloud-kubernetes-discoveryserver"); - Commons.waitForLogStatement("state received :", container, "spring-cloud-kubernetes-discoveryserver"); - - // 2. logs from discovery client - Commons.waitForLogStatement("using delay : 3000", container, - "spring-cloud-kubernetes-k8s-client-discovery-server"); - Commons.waitForLogStatement("state received : ", container, - "spring-cloud-kubernetes-k8s-client-discovery-server"); - - // 3. heartbeat listener message - WebClient.Builder builder = builder(); - WebClient client = builder.baseUrl("http://localhost:80/discoveryclient-it/state").build(); - String result = client.method(HttpMethod.GET) - .retrieve() - .bodyToMono(String.class) - .retryWhen(retrySpec()) - .block(); - - Condition> wireMockService = new Condition<>( - map -> map.entrySet().stream().anyMatch(en -> en.getValue().contains("service-wiremock-deployment")), - ""); - - Condition> discoveryServerService = new Condition<>(map -> map.entrySet() - .stream() - .anyMatch(en -> en.getValue().contains("spring-cloud-kubernetes-k8s-client-discovery-server")), ""); - - Assertions.assertThat(BASIC_JSON_TESTER.from(result)) - .>extractingJsonPathArrayValue("$.[*]") - .areAtLeastOne(wireMockService); - - Assertions.assertThat(BASIC_JSON_TESTER.from(result)) - .>extractingJsonPathArrayValue("$.[*]") - .areAtLeastOne(discoveryServerService); - } - - private static WebClient.Builder builder() { - return WebClient.builder().clientConnector(new ReactorClientHttpConnector(HttpClient.create())); - } - - private static RetryBackoffSpec retrySpec() { - return Retry.fixedDelay(15, Duration.ofSeconds(1)).filter(Objects::nonNull); - } - -} diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/java/org/springframework/cloud/kubernetes/discoveryclient/it/DiscoveryClientIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/java/org/springframework/cloud/kubernetes/discoveryclient/it/DiscoveryClientIT.java deleted file mode 100644 index cf13a089ef..0000000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/java/org/springframework/cloud/kubernetes/discoveryclient/it/DiscoveryClientIT.java +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Copyright 2013-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.kubernetes.discoveryclient.it; - -import java.time.Duration; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.TimeUnit; - -import io.kubernetes.client.openapi.apis.RbacAuthorizationV1Api; -import io.kubernetes.client.openapi.models.V1ClusterRoleBinding; -import io.kubernetes.client.openapi.models.V1Deployment; -import io.kubernetes.client.openapi.models.V1Ingress; -import io.kubernetes.client.openapi.models.V1Service; -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.testcontainers.k3s.K3sContainer; -import reactor.netty.http.client.HttpClient; -import reactor.util.retry.Retry; -import reactor.util.retry.RetryBackoffSpec; - -import org.springframework.boot.test.json.BasicJsonTester; -import org.springframework.cloud.kubernetes.integration.tests.commons.Commons; -import org.springframework.cloud.kubernetes.integration.tests.commons.Images; -import org.springframework.cloud.kubernetes.integration.tests.commons.Phase; -import org.springframework.cloud.kubernetes.integration.tests.commons.native_client.Util; -import org.springframework.http.HttpMethod; -import org.springframework.http.client.reactive.ReactorClientHttpConnector; -import org.springframework.web.reactive.function.client.WebClient; - -import static org.springframework.cloud.kubernetes.discoveryclient.it.DiscoveryClientFilterNamespaceDelegate.testNamespaceDiscoveryClient; -import static org.springframework.cloud.kubernetes.integration.tests.commons.native_client.Util.patchWithReplace; - -/** - * @author Ryan Baxter - */ -class DiscoveryClientIT { - - private static final String BODY_ONE = """ - { - "spec": { - "template": { - "spec": { - "containers": [{ - "name": "spring-cloud-kubernetes-k8s-client-discovery-server", - "image": "image_name_here", - "env": [ - { - "name": "SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0", - "value": "left" - }, - { - "name": "SPRING_CLOUD_KUBERNETES_DISCOVERY_CATALOGSERVICESWATCHDELAY", - "value": "3000" - }, - { - "name": "LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_DISCOVERY", - "value": "DEBUG" - }, - { - "name": "SPRING_CLOUD_KUBERNETES_HTTP_DISCOVERY_CATALOG_WATCHER_ENABLED", - "value": "TRUE" - } - ] - }] - } - } - } - } - """; - - private static final String BODY_TWO = """ - { - "spec": { - "template": { - "spec": { - "containers": [{ - "name": "spring-cloud-kubernetes-k8s-client-discovery-server", - "image": "image_name_here", - "env": [ - { - "name": "SPRING_CLOUD_KUBERNETES_DISCOVERY_ALL_NAMESPACES", - "value": "TRUE" - }, - { - "name": "LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_DISCOVERYSERVER", - "value": "DEBUG" - }, - { - "name": "SPRING_CLOUD_KUBERNETES_DISCOVERY_CATALOGSERVICESWATCHDELAY", - "value": "3000" - }, - { - "name": "SPRING_CLOUD_KUBERNETES_HTTP_DISCOVERY_CATALOG_WATCHER_ENABLED", - "value": "TRUE" - } - ] - }] - } - } - } - } - """; - - private static final Map POD_LABELS = Map.of("app", - "spring-cloud-kubernetes-k8s-client-discovery-server"); - - private static final Map POD_LABELS_DISCOVERY = Map.of("app", - "spring-cloud-kubernetes-discoveryserver"); - - private static final BasicJsonTester BASIC_JSON_TESTER = new BasicJsonTester(DiscoveryClientIT.class); - - private static final String DISCOVERY_SERVER_APP_NAME = "spring-cloud-kubernetes-discoveryserver"; - - private static final String SPRING_CLOUD_K8S_DISCOVERY_CLIENT_APP_NAME = "spring-cloud-kubernetes-k8s-client-discovery-server"; - - private static final String NAMESPACE = "default"; - - private static final String NAMESPACE_LEFT = "left"; - - private static final String NAMESPACE_RIGHT = "right"; - - private static final K3sContainer K3S = Commons.container(); - - private static Util util; - - private static RbacAuthorizationV1Api rbacApi; - - private static V1ClusterRoleBinding clusterRoleBinding; - - @BeforeAll - static void beforeAll() throws Exception { - K3S.start(); - - Commons.validateImage(DISCOVERY_SERVER_APP_NAME, K3S); - Commons.loadSpringCloudKubernetesImage(DISCOVERY_SERVER_APP_NAME, K3S); - - Commons.validateImage(SPRING_CLOUD_K8S_DISCOVERY_CLIENT_APP_NAME, K3S); - Commons.loadSpringCloudKubernetesImage(SPRING_CLOUD_K8S_DISCOVERY_CLIENT_APP_NAME, K3S); - - Images.loadWiremock(K3S); - - util = new Util(K3S); - rbacApi = new RbacAuthorizationV1Api(); - util.setUp(NAMESPACE); - - util.createNamespace(NAMESPACE_LEFT); - util.createNamespace(NAMESPACE_RIGHT); - - clusterRoleBinding = (V1ClusterRoleBinding) util - .yaml("namespace-filter/cluster-admin-serviceaccount-role.yaml"); - rbacApi.createClusterRoleBinding(clusterRoleBinding, null, null, null, null); - - util.wiremock(NAMESPACE_LEFT, "/wiremock-" + NAMESPACE_LEFT, Phase.CREATE, false); - util.wiremock(NAMESPACE_RIGHT, "/wiremock-" + NAMESPACE_RIGHT, Phase.CREATE, false); - - discoveryServer(Phase.CREATE); - - } - - @AfterAll - static void afterAll() throws Exception { - rbacApi.deleteClusterRoleBinding(clusterRoleBinding.getMetadata().getName(), null, null, null, null, null, - null); - util.wiremock(NAMESPACE_LEFT, "/wiremock-" + NAMESPACE_LEFT, Phase.DELETE, false); - util.wiremock(NAMESPACE_RIGHT, "/wiremock-" + NAMESPACE_RIGHT, Phase.DELETE, false); - - util.deleteNamespace(NAMESPACE_LEFT); - util.deleteNamespace(NAMESPACE_RIGHT); - - discoveryServer(Phase.DELETE); - discoveryClient(Phase.DELETE); - } - - @Test - void testDiscoveryClient() { - discoveryClient(Phase.CREATE); - testLoadBalancer(); - testHealth(); - - patchForAllNamespaces("docker.io/springcloud/spring-cloud-kubernetes-discoveryserver:" + Commons.pomVersion(), - "spring-cloud-kubernetes-discoveryserver-deployment", NAMESPACE); - patchForNamespaceFilter( - "docker.io/springcloud/spring-cloud-kubernetes-k8s-client-discovery-server:" + Commons.pomVersion(), - "spring-cloud-kubernetes-k8s-client-discovery-server-deployment", NAMESPACE); - testNamespaceDiscoveryClient(K3S); - } - - private void testLoadBalancer() { - WebClient.Builder builder = builder(); - WebClient serviceClient = builder.baseUrl("http://localhost:80/discoveryclient-it/services").build(); - - String result = serviceClient.method(HttpMethod.GET) - .retrieve() - .bodyToMono(String.class) - .retryWhen(retrySpec()) - .block(); - - Assertions.assertThat(BASIC_JSON_TESTER.from(result)) - .extractingJsonPathArrayValue("$") - .contains("spring-cloud-kubernetes-discoveryserver"); - - // since 'spring.cloud.kubernetes.http.discovery.client.catalog.watcher.enabled' - // is false by default, we will not receive any heartbeat events, - // simply because there are no beans registered to provide that to us. - // We assert this by doing a call to our internal /state - // endpoint, waiting 10 seconds and doing it again. Since the watch delay is set - // to 3 seconds, if there would be proper events, - // we would get a result that is different from '[]'. - - WebClient.Builder stateBuilder = builder(); - WebClient client = stateBuilder.baseUrl("http://localhost:80/discoveryclient-it/state").build(); - String stateResult = client.method(HttpMethod.GET) - .retrieve() - .bodyToMono(String.class) - .retryWhen(retrySpec()) - .block(); - Assertions.assertThat(BASIC_JSON_TESTER.from(stateResult)).isEqualTo("[]"); - - try { - Thread.sleep(TimeUnit.SECONDS.toMillis(10)); - } - catch (InterruptedException e) { - throw new RuntimeException(e); - } - - String stateResultAfter10Seconds = client.method(HttpMethod.GET) - .retrieve() - .bodyToMono(String.class) - .retryWhen(retrySpec()) - .block(); - Assertions.assertThat(BASIC_JSON_TESTER.from(stateResultAfter10Seconds)).isEqualTo("[]"); - } - - void testHealth() { - WebClient.Builder clientBuilder = builder(); - WebClient.Builder serverBuilder = builder(); - - WebClient client = clientBuilder.baseUrl("http://localhost:80/discoveryclient-it/actuator/health").build(); - WebClient server = serverBuilder.baseUrl("http://localhost:80/actuator/health").build(); - - String clientHealth = client.method(HttpMethod.GET) - .retrieve() - .bodyToMono(String.class) - .retryWhen(retrySpec()) - .block(); - String serverHealth = server.method(HttpMethod.GET) - .retrieve() - .bodyToMono(String.class) - .retryWhen(retrySpec()) - .block(); - - Assertions.assertThat(BASIC_JSON_TESTER.from(clientHealth)) - .extractingJsonPathStringValue("$.components.discoveryComposite.status") - .isEqualTo("UP"); - - Assertions.assertThat(BASIC_JSON_TESTER.from(serverHealth)) - .extractingJsonPathStringValue("$.components.kubernetes.status") - .isEqualTo("UP"); - } - - private static void discoveryClient(Phase phase) { - V1Deployment deployment = (V1Deployment) util - .yaml("client/spring-cloud-kubernetes-discoveryclient-it-deployment.yaml"); - V1Service service = (V1Service) util.yaml("client/spring-cloud-kubernetes-discoveryclient-it-service.yaml"); - V1Ingress ingress = (V1Ingress) util.yaml("ingress.yaml"); - - if (phase.equals(Phase.CREATE)) { - util.createAndWait(NAMESPACE, null, deployment, service, ingress, true); - } - else { - util.deleteAndWait(NAMESPACE, deployment, service, ingress); - } - } - - private static void discoveryServer(Phase phase) { - V1Deployment deployment = (V1Deployment) util - .yaml("server/spring-cloud-kubernetes-discoveryserver-deployment.yaml"); - V1Service service = (V1Service) util.yaml("server/spring-cloud-kubernetes-discoveryserver-service.yaml"); - - if (phase.equals(Phase.CREATE)) { - util.createAndWait(NAMESPACE, null, deployment, service, null, true); - } - else { - util.deleteAndWait(NAMESPACE, deployment, service, null); - } - } - - private WebClient.Builder builder() { - return WebClient.builder().clientConnector(new ReactorClientHttpConnector(HttpClient.create())); - } - - private RetryBackoffSpec retrySpec() { - return Retry.fixedDelay(15, Duration.ofSeconds(1)).filter(Objects::nonNull); - } - - static void patchForNamespaceFilter(String image, String deploymentName, String namespace) { - patchWithReplace(image, deploymentName, namespace, BODY_ONE, POD_LABELS); - } - - static void patchForAllNamespaces(String image, String deploymentName, String namespace) { - patchWithReplace(image, deploymentName, namespace, BODY_TWO, POD_LABELS_DISCOVERY); - } - -} diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/java/org/springframework/cloud/kubernetes/discoveryclient/it/DiscoveryServerClientBase.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/java/org/springframework/cloud/kubernetes/discoveryclient/it/DiscoveryServerClientBase.java new file mode 100644 index 0000000000..5506d4b385 --- /dev/null +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/java/org/springframework/cloud/kubernetes/discoveryclient/it/DiscoveryServerClientBase.java @@ -0,0 +1,150 @@ +/* + * Copyright 2013-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.kubernetes.discoveryclient.it; + +import java.io.IOException; +import java.io.StringReader; +import java.time.Duration; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.openapi.apis.CoreV1Api; +import io.kubernetes.client.openapi.apis.RbacAuthorizationV1Api; +import io.kubernetes.client.openapi.models.V1ClusterRoleBinding; +import io.kubernetes.client.openapi.models.V1Deployment; +import io.kubernetes.client.openapi.models.V1Service; +import io.kubernetes.client.util.Config; +import org.awaitility.Awaitility; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.extension.ExtendWith; +import org.testcontainers.k3s.K3sContainer; + +import org.springframework.boot.test.system.CapturedOutput; +import org.springframework.boot.test.system.OutputCaptureExtension; +import org.springframework.cloud.kubernetes.commons.discovery.EndpointNameAndNamespace; +import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; +import org.springframework.cloud.kubernetes.integration.tests.commons.Commons; +import org.springframework.cloud.kubernetes.integration.tests.commons.Phase; +import org.springframework.cloud.kubernetes.integration.tests.commons.native_client.Util; + +import static org.assertj.core.api.Assertions.assertThat; + +@ExtendWith(OutputCaptureExtension.class) +abstract class DiscoveryServerClientBase { + + private static final String DISCOVERY_SERVER_LABEL = "spring-cloud-kubernetes-discoveryserver"; + + protected static final String NAMESPACE = "default"; + + protected static final String NAMESPACE_LEFT = "left"; + + protected static final String NAMESPACE_RIGHT = "right"; + + protected static final String DISCOVERY_SERVER_APP_NAME = "spring-cloud-kubernetes-discoveryserver"; + + protected static final K3sContainer K3S = Commons.container(); + + protected static Util util; + + @BeforeAll + protected static void beforeAll() { + K3S.start(); + util = new Util(K3S); + } + + protected static ApiClient apiClient() { + String kubeConfigYaml = K3S.getKubeConfigYaml(); + + ApiClient client; + try { + client = Config.fromConfig(new StringReader(kubeConfigYaml)); + } + catch (IOException e) { + throw new RuntimeException(e); + } + return new CoreV1Api(client).getApiClient(); + } + + protected static KubernetesDiscoveryProperties discoveryProperties(Set namespaces) { + KubernetesDiscoveryProperties.Metadata metadata = new KubernetesDiscoveryProperties.Metadata(true, null, true, + null, true, "port.", true, true); + return new KubernetesDiscoveryProperties(true, false, namespaces, true, 60, false, null, Set.of(443, 8443), + Map.of(), null, metadata, 0, false, true, "http://localhost:32321"); + } + + protected static void discoveryServer(Phase phase) { + V1Deployment deployment = (V1Deployment) util.yaml("manifests/discoveryserver-deployment.yaml"); + V1Service service = (V1Service) util.yaml("manifests/discoveryserver-service.yaml"); + + if (phase.equals(Phase.CREATE)) { + util.createAndWait(NAMESPACE, null, deployment, service, null, true); + } + else { + util.deleteAndWait(NAMESPACE, deployment, service, null); + } + } + + protected static void serviceAccount(Phase phase) { + + try { + V1ClusterRoleBinding clusterRoleBinding = (V1ClusterRoleBinding) util.yaml("manifests/cluster-role.yaml"); + RbacAuthorizationV1Api rbacApi = new RbacAuthorizationV1Api(); + + if (phase == Phase.CREATE) { + rbacApi.createClusterRoleBinding(clusterRoleBinding, null, null, null, null); + } + else { + rbacApi.deleteClusterRoleBinding(clusterRoleBinding.getMetadata().getName(), null, null, null, null, + null, null); + } + } + catch (Exception e) { + throw new RuntimeException(e); + } + + } + + protected static void testHeartBeat(HeartbeatListener heartbeatListener, CapturedOutput output) { + + // 1. logs from discovery server + Commons.waitForLogStatement("using delay : 3000", K3S, DISCOVERY_SERVER_LABEL); + Commons.waitForLogStatement("received heartbeat event", K3S, DISCOVERY_SERVER_LABEL); + Commons.waitForLogStatement("state received :", K3S, DISCOVERY_SERVER_LABEL); + + // 2. logs from discovery client + assertThat(output.getOut()).contains("using delay : 3000"); + assertThat(output.getOut()).contains("state received : "); + assertThat(output.getOut()).contains("received heartbeat event in listener"); + + // 3. heartbeat listener message + List result = heartbeatListener.state.get(); + Awaitility.await() + .atMost(Duration.ofSeconds(60)) + .pollInterval(Duration.ofSeconds(1)) + .until(() -> result.size() == 2); + + List namespaces = result.stream().map(EndpointNameAndNamespace::namespace).toList(); + assertThat(namespaces).containsExactlyInAnyOrder(NAMESPACE_LEFT, NAMESPACE_RIGHT); + + List endpointNames = result.stream().map(EndpointNameAndNamespace::endpointName).toList(); + assertThat(endpointNames.get(0)).contains("service-wiremock-deployment"); + assertThat(endpointNames.get(1)).contains("service-wiremock-deployment"); + } + +} diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/java/org/springframework/cloud/kubernetes/discoveryclient/it/DiscoveryServerClientIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/java/org/springframework/cloud/kubernetes/discoveryclient/it/DiscoveryServerClientIT.java new file mode 100644 index 0000000000..ab3de7a6bb --- /dev/null +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/java/org/springframework/cloud/kubernetes/discoveryclient/it/DiscoveryServerClientIT.java @@ -0,0 +1,166 @@ +/* + * Copyright 2013-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.kubernetes.discoveryclient.it; + +import java.util.List; +import java.util.Set; + +import io.kubernetes.client.openapi.ApiClient; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.test.system.CapturedOutput; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient; +import org.springframework.cloud.kubernetes.commons.discovery.DefaultKubernetesServiceInstance; +import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; +import org.springframework.cloud.kubernetes.integration.tests.commons.Commons; +import org.springframework.cloud.kubernetes.integration.tests.commons.Images; +import org.springframework.cloud.kubernetes.integration.tests.commons.Phase; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.test.context.TestPropertySource; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author wind57 + */ +@SpringBootTest(classes = { App.class, DiscoveryServerClientIT.TestConfig.class }, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@TestPropertySource(properties = { "spring.main.cloud-platform=kubernetes", + "logging.level.org.springframework.cloud.kubernetes.discovery=debug", + "spring.cloud.kubernetes.discovery.catalogServicesWatchDelay=3000", + "spring.cloud.kubernetes.http.discovery.catalog.watcher.enabled=true" }) +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +class DiscoveryServerClientIT extends DiscoveryServerClientBase { + + @Autowired + private DiscoveryClient discoveryClient; + + @Autowired + private ReactiveDiscoveryClient reactiveDiscoveryClient; + + @Autowired + private HeartbeatListener heartbeatListener; + + @BeforeAll + static void beforeAllLocal() throws Exception { + util.createNamespace(NAMESPACE_LEFT); + util.createNamespace(NAMESPACE_RIGHT); + + Commons.validateImage(DISCOVERY_SERVER_APP_NAME, K3S); + Commons.loadSpringCloudKubernetesImage(DISCOVERY_SERVER_APP_NAME, K3S); + util.setUp(NAMESPACE); + serviceAccount(Phase.CREATE); + discoveryServer(Phase.CREATE); + + Images.loadWiremock(K3S); + util.wiremock(NAMESPACE_LEFT, "/wiremock-" + NAMESPACE_LEFT, Phase.CREATE, false); + util.wiremock(NAMESPACE_RIGHT, "/wiremock-" + NAMESPACE_RIGHT, Phase.CREATE, false); + } + + @AfterAll + static void afterAllLocal() { + serviceAccount(Phase.DELETE); + discoveryServer(Phase.DELETE); + + util.wiremock(NAMESPACE_LEFT, "/wiremock-" + NAMESPACE_LEFT, Phase.DELETE, false); + util.wiremock(NAMESPACE_RIGHT, "/wiremock-" + NAMESPACE_RIGHT, Phase.DELETE, false); + + util.deleteNamespace(NAMESPACE_LEFT); + util.deleteNamespace(NAMESPACE_RIGHT); + } + + /** + *
+	 *     - searching is enabled in two namespaces : left and right
+	 * 
+ */ + @Test + @Order(1) + void testBlocking(CapturedOutput output) { + List services = reactiveDiscoveryClient.getServices().collectList().block(); + assertThat(services).hasSize(1); + assertThat(services).contains("service-wiremock"); + + List serviceInstances = reactiveDiscoveryClient.getInstances("service-wiremock") + .collectList() + .block(); + List defaultKubernetesServiceInstances = serviceInstances.stream() + .map(x -> (DefaultKubernetesServiceInstance) x) + .toList(); + assertThat(defaultKubernetesServiceInstances).hasSize(2); + + List namespaces = defaultKubernetesServiceInstances.stream() + .map(DefaultKubernetesServiceInstance::getNamespace) + .toList(); + assertThat(namespaces).containsExactlyInAnyOrder(NAMESPACE_LEFT, NAMESPACE_RIGHT); + + testHeartBeat(heartbeatListener, output); + } + + /** + *
+	 *     - searching is enabled in two namespaces : left and right
+	 * 
+ */ + @Test + @Order(2) + void testReactive() { + List services = discoveryClient.getServices(); + assertThat(services).hasSize(1); + assertThat(services).contains("service-wiremock"); + + List serviceInstances = discoveryClient.getInstances("service-wiremock"); + List defaultKubernetesServiceInstances = serviceInstances.stream() + .map(x -> (DefaultKubernetesServiceInstance) x) + .toList(); + assertThat(defaultKubernetesServiceInstances).hasSize(2); + + List namespaces = defaultKubernetesServiceInstances.stream() + .map(DefaultKubernetesServiceInstance::getNamespace) + .toList(); + assertThat(namespaces).containsExactlyInAnyOrder(NAMESPACE_LEFT, NAMESPACE_RIGHT); + } + + @TestConfiguration + static class TestConfig { + + @Bean + @Primary + ApiClient client() { + return apiClient(); + } + + @Bean + @Primary + KubernetesDiscoveryProperties kubernetesDiscoveryProperties() { + return discoveryProperties(Set.of(NAMESPACE_LEFT, NAMESPACE_RIGHT)); + } + + } + +} diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/client/spring-cloud-kubernetes-discoveryclient-it-deployment.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/client/spring-cloud-kubernetes-discoveryclient-it-deployment.yaml deleted file mode 100644 index 21ce9fd42b..0000000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/client/spring-cloud-kubernetes-discoveryclient-it-deployment.yaml +++ /dev/null @@ -1,37 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: spring-cloud-kubernetes-k8s-client-discovery-server-deployment -spec: - selector: - matchLabels: - app: spring-cloud-kubernetes-k8s-client-discovery-server - template: - metadata: - labels: - app: spring-cloud-kubernetes-k8s-client-discovery-server - spec: - serviceAccountName: spring-cloud-kubernetes-serviceaccount - containers: - - name: spring-cloud-kubernetes-k8s-client-discovery-server - image: docker.io/springcloud/spring-cloud-kubernetes-k8s-client-discovery-server - imagePullPolicy: IfNotPresent - readinessProbe: - httpGet: - port: 8080 - path: /discoveryclient-it/actuator/health/readiness - initialDelaySeconds: 10 - periodSeconds: 2 - failureThreshold: 3 - livenessProbe: - httpGet: - port: 8080 - path: /discoveryclient-it/actuator/health/liveness - initialDelaySeconds: 10 - periodSeconds: 2 - failureThreshold: 3 - env: - - name: SPRING_CLOUD_KUBERNETES_DISCOVERY_CATALOGSERVICESWATCHDELAY - value: "3000" - ports: - - containerPort: 8080 diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/client/spring-cloud-kubernetes-discoveryclient-it-service.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/client/spring-cloud-kubernetes-discoveryclient-it-service.yaml deleted file mode 100644 index 306edf2ba0..0000000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/client/spring-cloud-kubernetes-discoveryclient-it-service.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: spring-cloud-kubernetes-k8s-client-discovery-server - name: spring-cloud-kubernetes-k8s-client-discovery-server -spec: - ports: - - name: http - port: 8080 - targetPort: 8080 - selector: - app: spring-cloud-kubernetes-k8s-client-discovery-server - type: ClusterIP diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/ingress.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/ingress.yaml deleted file mode 100644 index 9635d979b7..0000000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/ingress.yaml +++ /dev/null @@ -1,24 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: it-ingress - namespace: default -spec: - rules: - - http: - paths: - - path: /discoveryclient-it - pathType: Prefix - backend: - service: - name: spring-cloud-kubernetes-k8s-client-discovery-server - port: - number: 8080 - - - path: / - pathType: Prefix - backend: - service: - name: spring-cloud-kubernetes-discoveryserver - port: - number: 80 diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/namespace-filter/cluster-admin-serviceaccount-role.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/manifests/cluster-role.yaml similarity index 100% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/namespace-filter/cluster-admin-serviceaccount-role.yaml rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/manifests/cluster-role.yaml diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/server/spring-cloud-kubernetes-discoveryserver-deployment.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/manifests/discoveryserver-deployment.yaml similarity index 72% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/server/spring-cloud-kubernetes-discoveryserver-deployment.yaml rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/manifests/discoveryserver-deployment.yaml index 522f92bae6..a0d46268d5 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/server/spring-cloud-kubernetes-discoveryserver-deployment.yaml +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/manifests/discoveryserver-deployment.yaml @@ -18,20 +18,28 @@ spec: imagePullPolicy: IfNotPresent readinessProbe: httpGet: - port: 8761 + port: 32321 path: /actuator/health/readiness livenessProbe: httpGet: - port: 8761 + port: 32321 path: /actuator/health/liveness env: - name: LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_DISCOVERYSERVER value: "DEBUG" - name: SPRING_CLOUD_KUBERNETES_DISCOVERY_CATALOGSERVICESWATCHDELAY value: "3000" + - name: SPRING_CLOUD_KUBERNETES_HTTP_DISCOVERY_CATALOG_WATCHER_ENABLED + value: "TRUE" - name: MANAGEMENT_ENDPOINT_HEALTH_SHOWCOMPONENTS value: "ALWAYS" - name: MANAGEMENT_ENDPOINT_HEALTH_SHOWDETAILS value: "ALWAYS" + - name: SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0 + value: left + - name: SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_1 + value: right + - name: SERVER_PORT + value: "32321" ports: - - containerPort: 8761 + - containerPort: 32321 diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/server/spring-cloud-kubernetes-discoveryserver-service.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/manifests/discoveryserver-service.yaml similarity index 74% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/server/spring-cloud-kubernetes-discoveryserver-service.yaml rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/manifests/discoveryserver-service.yaml index ba99611826..430026b2ab 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/server/spring-cloud-kubernetes-discoveryserver-service.yaml +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery-server/src/test/resources/manifests/discoveryserver-service.yaml @@ -7,8 +7,9 @@ metadata: spec: ports: - name: http - port: 80 - targetPort: 8761 + port: 32321 + targetPort: 32321 + nodePort: 32321 selector: app: spring-cloud-kubernetes-discoveryserver - type: ClusterIP + type: NodePort diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery/src/test/java/org/springframework/cloud/kubernetes/k8s/client/discovery/KubernetesClientReactiveIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery/src/test/java/org/springframework/cloud/kubernetes/k8s/client/discovery/KubernetesClientReactiveIT.java index cf609142ef..2f00f4f198 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery/src/test/java/org/springframework/cloud/kubernetes/k8s/client/discovery/KubernetesClientReactiveIT.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery/src/test/java/org/springframework/cloud/kubernetes/k8s/client/discovery/KubernetesClientReactiveIT.java @@ -28,7 +28,7 @@ import org.springframework.boot.test.context.TestConfiguration; import org.springframework.boot.test.system.CapturedOutput; import org.springframework.boot.test.web.server.LocalManagementPort; -import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient; import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; import org.springframework.cloud.kubernetes.integration.tests.commons.Images; import org.springframework.cloud.kubernetes.integration.tests.commons.Phase; @@ -55,7 +55,7 @@ class KubernetesClientReactiveIT extends KubernetesClientDiscoveryBase { private int port; @Autowired - private DiscoveryClient discoveryClient; + private ReactiveDiscoveryClient discoveryClient; @BeforeEach void beforeEach() { diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery/src/test/java/org/springframework/cloud/kubernetes/k8s/client/discovery/TestAssertions.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery/src/test/java/org/springframework/cloud/kubernetes/k8s/client/discovery/TestAssertions.java index dd86ad7437..8c0a8c62d7 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery/src/test/java/org/springframework/cloud/kubernetes/k8s/client/discovery/TestAssertions.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-discovery/src/test/java/org/springframework/cloud/kubernetes/k8s/client/discovery/TestAssertions.java @@ -24,6 +24,7 @@ import org.springframework.boot.test.system.CapturedOutput; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient; import org.springframework.cloud.kubernetes.commons.discovery.DefaultKubernetesServiceInstance; import org.springframework.http.HttpMethod; import org.springframework.web.reactive.function.client.WebClient; @@ -137,4 +138,18 @@ static void assertPodMetadata(DiscoveryClient discoveryClient) { } + static void assertPodMetadata(ReactiveDiscoveryClient discoveryClient) { + + List serviceInstances = discoveryClient.getInstances("service-wiremock").collectList().block(); + assertThat(serviceInstances).hasSize(1); + DefaultKubernetesServiceInstance wiremockInstance = (DefaultKubernetesServiceInstance) serviceInstances.get(0); + + assertThat(wiremockInstance.getServiceId()).isEqualTo("service-wiremock"); + assertThat(wiremockInstance.getInstanceId()).isNotNull(); + assertThat(wiremockInstance.getHost()).isNotNull(); + assertThat(wiremockInstance.getMetadata()).isEqualTo(Map.of("k8s_namespace", "default", "type", "ClusterIP", + "port.http", "8080", "app", "service-wiremock")); + + } + }