refactor k8s discovery server integration tests (#1877)
* started Signed-off-by: wind57 <eugen.rabii@gmail.com> * dirty Signed-off-by: wind57 <eugen.rabii@gmail.com> * fix Signed-off-by: wind57 <eugen.rabii@gmail.com> * fix test Signed-off-by: wind57 <eugen.rabii@gmail.com> * fix test Signed-off-by: wind57 <eugen.rabii@gmail.com> --------- Signed-off-by: wind57 <eugen.rabii@gmail.com>
This commit is contained in:
@@ -11,6 +11,11 @@
|
||||
|
||||
<artifactId>spring-cloud-kubernetes-k8s-client-discovery-server</artifactId>
|
||||
|
||||
<properties>
|
||||
<spring-boot.repackage.skip>true</spring-boot.repackage.skip>
|
||||
<spring-boot.build-image.skip>true</spring-boot.build-image.skip>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@@ -43,10 +48,6 @@
|
||||
<directory>../src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -35,12 +35,12 @@ class HeartbeatListener implements ApplicationListener<HeartbeatEvent> {
|
||||
|
||||
private static final LogAccessor LOG = new LogAccessor(LogFactory.getLog(HeartbeatListener.class));
|
||||
|
||||
AtomicReference<List<EndpointNameAndNamespace>> state = new AtomicReference<>(List.of());
|
||||
public final AtomicReference<List<EndpointNameAndNamespace>> 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<EndpointNameAndNamespace> state = (List<EndpointNameAndNamespace>) event.getValue();
|
||||
this.state.set(state);
|
||||
LOG.info("state received : " + state);
|
||||
|
||||
@@ -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<String> services() {
|
||||
return discoveryClient.getServices();
|
||||
}
|
||||
|
||||
@GetMapping("/service/{serviceId}")
|
||||
List<ServiceInstance> service(@PathVariable String serviceId) {
|
||||
return discoveryClient.getInstances(serviceId);
|
||||
}
|
||||
|
||||
@GetMapping("/state")
|
||||
List<EndpointNameAndNamespace> state() {
|
||||
return heartbeatListener.state.get();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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: "*"
|
||||
@@ -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<LinkedHashMap<String, String>> wireMockService = new Condition<>(
|
||||
map -> map.entrySet().stream().anyMatch(en -> en.getValue().contains("service-wiremock-deployment")),
|
||||
"");
|
||||
|
||||
Condition<LinkedHashMap<String, String>> 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))
|
||||
.<LinkedHashMap<String, String>>extractingJsonPathArrayValue("$.[*]")
|
||||
.areAtLeastOne(wireMockService);
|
||||
|
||||
Assertions.assertThat(BASIC_JSON_TESTER.from(result))
|
||||
.<LinkedHashMap<String, String>>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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<String, String> POD_LABELS = Map.of("app",
|
||||
"spring-cloud-kubernetes-k8s-client-discovery-server");
|
||||
|
||||
private static final Map<String, String> 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<String> 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<EndpointNameAndNamespace> result = heartbeatListener.state.get();
|
||||
Awaitility.await()
|
||||
.atMost(Duration.ofSeconds(60))
|
||||
.pollInterval(Duration.ofSeconds(1))
|
||||
.until(() -> result.size() == 2);
|
||||
|
||||
List<String> namespaces = result.stream().map(EndpointNameAndNamespace::namespace).toList();
|
||||
assertThat(namespaces).containsExactlyInAnyOrder(NAMESPACE_LEFT, NAMESPACE_RIGHT);
|
||||
|
||||
List<String> endpointNames = result.stream().map(EndpointNameAndNamespace::endpointName).toList();
|
||||
assertThat(endpointNames.get(0)).contains("service-wiremock-deployment");
|
||||
assertThat(endpointNames.get(1)).contains("service-wiremock-deployment");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - searching is enabled in two namespaces : left and right
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
@Order(1)
|
||||
void testBlocking(CapturedOutput output) {
|
||||
List<String> services = reactiveDiscoveryClient.getServices().collectList().block();
|
||||
assertThat(services).hasSize(1);
|
||||
assertThat(services).contains("service-wiremock");
|
||||
|
||||
List<ServiceInstance> serviceInstances = reactiveDiscoveryClient.getInstances("service-wiremock")
|
||||
.collectList()
|
||||
.block();
|
||||
List<DefaultKubernetesServiceInstance> defaultKubernetesServiceInstances = serviceInstances.stream()
|
||||
.map(x -> (DefaultKubernetesServiceInstance) x)
|
||||
.toList();
|
||||
assertThat(defaultKubernetesServiceInstances).hasSize(2);
|
||||
|
||||
List<String> namespaces = defaultKubernetesServiceInstances.stream()
|
||||
.map(DefaultKubernetesServiceInstance::getNamespace)
|
||||
.toList();
|
||||
assertThat(namespaces).containsExactlyInAnyOrder(NAMESPACE_LEFT, NAMESPACE_RIGHT);
|
||||
|
||||
testHeartBeat(heartbeatListener, output);
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - searching is enabled in two namespaces : left and right
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
@Order(2)
|
||||
void testReactive() {
|
||||
List<String> services = discoveryClient.getServices();
|
||||
assertThat(services).hasSize(1);
|
||||
assertThat(services).contains("service-wiremock");
|
||||
|
||||
List<ServiceInstance> serviceInstances = discoveryClient.getInstances("service-wiremock");
|
||||
List<DefaultKubernetesServiceInstance> defaultKubernetesServiceInstances = serviceInstances.stream()
|
||||
.map(x -> (DefaultKubernetesServiceInstance) x)
|
||||
.toList();
|
||||
assertThat(defaultKubernetesServiceInstances).hasSize(2);
|
||||
|
||||
List<String> 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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -28,7 +28,7 @@ import org.springframework.boot.test.context.SpringBootTest;
|
||||
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() {
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.springframework.boot.test.json.BasicJsonTester;
|
||||
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 @@ final class TestAssertions {
|
||||
|
||||
}
|
||||
|
||||
static void assertPodMetadata(ReactiveDiscoveryClient discoveryClient) {
|
||||
|
||||
List<ServiceInstance> 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"));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user