diff --git a/.github/workflows/composites/maven-build-with-dry-run-for-tests/action.yaml b/.github/workflows/composites/maven-build-with-dry-run-for-tests/action.yaml
index 15b6b7f1..aec179be 100644
--- a/.github/workflows/composites/maven-build-with-dry-run-for-tests/action.yaml
+++ b/.github/workflows/composites/maven-build-with-dry-run-for-tests/action.yaml
@@ -13,6 +13,7 @@ runs:
-T 1C > /tmp/tests.txt
- name: show result
+ if: always()
shell: bash
run: cat /tmp/tests.txt
diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryClientIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryClientIT.java
index 0d85418f..b3deeb1c 100644
--- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryClientIT.java
+++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryClientIT.java
@@ -31,7 +31,10 @@ import io.kubernetes.client.openapi.models.V1Service;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
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.testcontainers.containers.Container;
import org.testcontainers.k3s.K3sContainer;
import reactor.netty.http.client.HttpClient;
@@ -51,6 +54,7 @@ import org.springframework.web.reactive.function.client.WebClient;
/**
* @author wind57
*/
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class KubernetesClientDiscoveryClientIT {
private static final String NAMESPACE = "default";
@@ -61,6 +65,12 @@ class KubernetesClientDiscoveryClientIT {
private static final String IMAGE_NAME = "spring-cloud-kubernetes-client-discovery-it";
+ private static final String DEPLOYMENT_NAME = "spring-cloud-kubernetes-client-discovery-deployment-it";
+
+ private static final String NAMESPACE_A_UAT = "a-uat";
+
+ private static final String NAMESPACE_B_UAT = "b-uat";
+
private static Util util;
private static final K3sContainer K3S = Commons.container();
@@ -72,11 +82,13 @@ class KubernetesClientDiscoveryClientIT {
Commons.loadSpringCloudKubernetesImage(IMAGE_NAME, K3S);
util = new Util(K3S);
- Commons.systemPrune();
+ util.setUp(NAMESPACE);
+ manifests(Phase.CREATE);
}
@AfterAll
- static void after() throws Exception {
+ static void afterAll() throws Exception {
+ manifests(Phase.DELETE);
Commons.cleanUp(IMAGE_NAME, K3S);
}
@@ -85,11 +97,9 @@ class KubernetesClientDiscoveryClientIT {
* explicit namespace and 'default' must be picked-up.
*/
@Test
+ @Order(1)
void testSimple() {
- // set-up
- util.setUp(NAMESPACE);
- manifests(false, null, Phase.CREATE);
util.busybox(NAMESPACE, Phase.CREATE);
Assertions.assertTrue(logs().contains("serviceSharedInformer will use namespace : default"));
@@ -148,7 +158,6 @@ class KubernetesClientDiscoveryClientIT {
// clean-up
util.busybox(NAMESPACE, Phase.DELETE);
- manifests(false, null, Phase.DELETE);
}
/**
@@ -161,13 +170,17 @@ class KubernetesClientDiscoveryClientIT {
*
*/
@Test
+ @Order(2)
void testAllNamespaces() {
util.createNamespace(NAMESPACE_A);
util.createNamespace(NAMESPACE_B);
util.setUpClusterWideClusterRoleBinding(NAMESPACE);
util.wiremock(NAMESPACE_A, "/wiremock", Phase.CREATE);
util.busybox(NAMESPACE_B, Phase.CREATE);
- manifests(true, null, Phase.CREATE);
+
+ KubernetesClientDiscoveryClientUtils.patchForAllNamespaces(DEPLOYMENT_NAME, NAMESPACE);
+ util.waitForDeploymentAfterPatch(DEPLOYMENT_NAME, NAMESPACE,
+ Map.of("app", "spring-cloud-kubernetes-client-discovery-it"));
Assertions.assertTrue(logs().contains("serviceSharedInformer will use all-namespaces"));
@@ -193,12 +206,9 @@ class KubernetesClientDiscoveryClientIT {
Assertions.assertEquals(resultForNonExistentService.size(), 0);
- manifests(true, null, Phase.DELETE);
- util.wiremock(NAMESPACE_A, "/wiremock", Phase.DELETE);
+ // do not remove wiremock in namespace a, it is required in the next test
util.busybox(NAMESPACE_B, Phase.DELETE);
util.deleteClusterWideClusterRoleBinding(NAMESPACE);
- util.deleteNamespace(NAMESPACE_A);
- util.deleteNamespace(NAMESPACE_B);
}
/**
@@ -211,13 +221,14 @@ class KubernetesClientDiscoveryClientIT {
*
*/
@Test
+ @Order(3)
void testSpecificNamespace() {
- util.createNamespace(NAMESPACE_A);
- util.createNamespace(NAMESPACE_B);
util.setUpClusterWide(NAMESPACE, Set.of(NAMESPACE, NAMESPACE_A));
- util.wiremock(NAMESPACE_A, "/wiremock", Phase.CREATE);
util.wiremock(NAMESPACE_B, "/wiremock", Phase.CREATE);
- manifests(false, NAMESPACE_A, Phase.CREATE);
+
+ KubernetesClientDiscoveryClientUtils.patchForSingleNamespace(DEPLOYMENT_NAME, NAMESPACE);
+ util.waitForDeploymentAfterPatch(DEPLOYMENT_NAME, NAMESPACE,
+ Map.of("app", "spring-cloud-kubernetes-client-discovery-it"));
// first check that wiremock service is present in both namespaces a and b
assertServicePresentInNamespaces(List.of("a", "b"), "service-wiremock", "service-wiremock");
@@ -259,7 +270,6 @@ class KubernetesClientDiscoveryClientIT {
Assertions.assertEquals(resultForNonExistentService.size(), 0);
- manifests(false, NAMESPACE_A, Phase.DELETE);
util.wiremock(NAMESPACE_A, "/wiremock", Phase.DELETE);
util.wiremock(NAMESPACE_B, "/wiremock", Phase.DELETE);
util.deleteClusterWide(NAMESPACE, Set.of(NAMESPACE, NAMESPACE_A));
@@ -267,41 +277,122 @@ class KubernetesClientDiscoveryClientIT {
util.deleteNamespace(NAMESPACE_B);
}
- private static void manifests(boolean allNamespaces, String clientSpecificNamespace, Phase phase) {
+ @Test
+ @Order(4)
+ void testSimplePodMetadata() {
+ util.setUp(NAMESPACE);
+ String imageName = "docker.io/springcloud/spring-cloud-kubernetes-client-discovery-it:" + Commons.pomVersion();
+ KubernetesClientDiscoveryClientUtils.patchForPodMetadata(imageName, DEPLOYMENT_NAME, NAMESPACE);
+ util.waitForDeploymentAfterPatch(DEPLOYMENT_NAME, NAMESPACE,
+ Map.of("app", "spring-cloud-kubernetes-client-discovery-it"));
+ new KubernetesClientDiscoveryPodMetadataITDelegate().testSimple();
+ }
+
+ @Test
+ @Order(5)
+ void filterMatchesOneNamespaceViaThePredicate() {
+ String imageName = "docker.io/springcloud/spring-cloud-kubernetes-client-discovery-it:" + Commons.pomVersion();
+ KubernetesClientDiscoveryClientUtils.patchForUATNamespacesTests(imageName, DEPLOYMENT_NAME, NAMESPACE);
+ util.waitForDeploymentAfterPatch(DEPLOYMENT_NAME, NAMESPACE,
+ Map.of("app", "spring-cloud-kubernetes-client-discovery-it"));
+ new KubernetesClientDiscoveryFilterITDelegate().filterMatchesOneNamespaceViaThePredicate(util);
+
+ }
+
+ /**
+ *
+ * - service "wiremock" is present in namespace "a-uat"
+ * - service "wiremock" is present in namespace "b-uat"
+ *
+ * - we search with a predicate : "#root.metadata.namespace matches '^uat.*$'"
+ *
+ * As such, both services are found via 'getInstances' call.
+ *
+ */
+ @Test
+ @Order(6)
+ void filterMatchesBothNamespacesViaThePredicate() {
+
+ // patch the deployment to change what namespaces are take into account
+ KubernetesClientDiscoveryClientUtils.patchForTwoNamespacesMatchViaThePredicate(DEPLOYMENT_NAME, NAMESPACE);
+ util.waitForDeploymentAfterPatch(DEPLOYMENT_NAME, NAMESPACE,
+ Map.of("app", "spring-cloud-kubernetes-client-discovery-it"));
+
+ new KubernetesClientDiscoveryFilterITDelegate().filterMatchesBothNamespacesViaThePredicate(util);
+ }
+
+ @Test
+ @Order(7)
+ void testBlockingConfiguration() {
+
+ // filter tests are done, clean-up a bit to prepare everything for health tests
+ deleteNamespacesAndWiremock();
+
+ String imageName = "docker.io/springcloud/spring-cloud-kubernetes-client-discovery-it:" + Commons.pomVersion();
+ KubernetesClientDiscoveryClientUtils.patchForBlockingHealth(imageName, DEPLOYMENT_NAME, NAMESPACE);
+ util.waitForDeploymentAfterPatch(DEPLOYMENT_NAME, NAMESPACE,
+ Map.of("app", "spring-cloud-kubernetes-client-discovery-it"));
+
+ new KubernetesClientDiscoveryHealthITDelegate().testBlockingConfiguration(K3S);
+ }
+
+ @Test
+ @Order(8)
+ void testReactiveConfiguration() {
+
+ KubernetesClientDiscoveryClientUtils.patchForReactiveHealth(DEPLOYMENT_NAME, NAMESPACE);
+ util.waitForDeploymentAfterPatch(DEPLOYMENT_NAME, NAMESPACE,
+ Map.of("app", "spring-cloud-kubernetes-client-discovery-it"));
+
+ new KubernetesClientDiscoveryHealthITDelegate().testReactiveConfiguration(util, K3S);
+ }
+
+ @Test
+ @Order(9)
+ void testDefaultConfiguration() {
+
+ KubernetesClientDiscoveryClientUtils.patchForBlockingAndReactiveHealth(DEPLOYMENT_NAME, NAMESPACE);
+ util.waitForDeploymentAfterPatch(DEPLOYMENT_NAME, NAMESPACE,
+ Map.of("app", "spring-cloud-kubernetes-client-discovery-it"));
+
+ new KubernetesClientDiscoveryHealthITDelegate().testDefaultConfiguration(util, K3S);
+ }
+
+ private void deleteNamespacesAndWiremock() {
+ util.wiremock(NAMESPACE_A_UAT, "/wiremock", Phase.DELETE);
+ util.wiremock(NAMESPACE_B_UAT, "/wiremock", Phase.DELETE);
+ util.deleteNamespace(NAMESPACE_A_UAT);
+ util.deleteNamespace(NAMESPACE_B_UAT);
+ }
+
+ private static void manifests(Phase phase) {
V1Deployment deployment = (V1Deployment) util.yaml("kubernetes-discovery-deployment.yaml");
V1Service service = (V1Service) util.yaml("kubernetes-discovery-service.yaml");
V1Ingress ingress = (V1Ingress) util.yaml("kubernetes-discovery-ingress.yaml");
- List envVars = new ArrayList<>(
- Optional.ofNullable(deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv())
- .orElse(List.of()));
- V1EnvVar debugLevel = new V1EnvVar().name("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT_DISCOVERY")
- .value("DEBUG");
-
- V1EnvVar debugLevelForClient = new V1EnvVar().name("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT")
- .value("DEBUG");
-
- if (allNamespaces) {
- V1EnvVar allNamespacesVar = new V1EnvVar().name("SPRING_CLOUD_KUBERNETES_DISCOVERY_ALL_NAMESPACES")
- .value("TRUE");
- envVars.add(allNamespacesVar);
+ if (phase.equals(Phase.DELETE)) {
+ util.deleteAndWait(NAMESPACE, deployment, service, ingress);
+ return;
}
- if (clientSpecificNamespace != null) {
- V1EnvVar clientNamespace = new V1EnvVar().name("SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0")
- .value(NAMESPACE_A);
- envVars.add(clientNamespace);
- }
- envVars.add(debugLevel);
- envVars.add(debugLevelForClient);
- deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(envVars);
-
if (phase.equals(Phase.CREATE)) {
+
+ List envVars = new ArrayList<>(
+ Optional.ofNullable(deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv())
+ .orElse(List.of()));
+ V1EnvVar debugLevel = new V1EnvVar()
+ .name("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT_DISCOVERY").value("DEBUG");
+
+ V1EnvVar debugLevelForClient = new V1EnvVar()
+ .name("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT").value("DEBUG");
+
+ envVars.add(debugLevel);
+ envVars.add(debugLevelForClient);
+ deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(envVars);
+
util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
}
- else if (phase.equals(Phase.DELETE)) {
- util.deleteAndWait(NAMESPACE, deployment, service, ingress);
- }
+
}
private WebClient.Builder builder() {
diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryClientUtils.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryClientUtils.java
new file mode 100644
index 00000000..55093d05
--- /dev/null
+++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryClientUtils.java
@@ -0,0 +1,442 @@
+/*
+ * Copyright 2013-2023 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.client.discovery.it;
+
+import io.kubernetes.client.custom.V1Patch;
+import io.kubernetes.client.openapi.ApiException;
+import io.kubernetes.client.openapi.apis.AppsV1Api;
+import io.kubernetes.client.openapi.apis.CoreV1Api;
+import io.kubernetes.client.openapi.models.V1Deployment;
+import io.kubernetes.client.util.PatchUtils;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.core.log.LogAccessor;
+
+/**
+ * @author wind57
+ */
+final class KubernetesClientDiscoveryClientUtils {
+
+ private static final LogAccessor LOG = new LogAccessor(
+ LogFactory.getLog(KubernetesClientDiscoveryClientUtils.class));
+
+ // patch the filter so that it matches both namespaces
+ private static final String BODY_ONE = """
+ {
+ "spec": {
+ "template": {
+ "spec": {
+ "containers": [{
+ "name": "spring-cloud-kubernetes-client-discovery",
+ "env": [{
+ "name": "SPRING_CLOUD_KUBERNETES_DISCOVERY_FILTER",
+ "value": "#root.metadata.namespace matches '^.*uat$'"
+ }]
+ }]
+ }
+ }
+ }
+ }
+ """;
+
+ private static final String BODY_TWO = """
+ {
+ "spec": {
+ "template": {
+ "spec": {
+ "containers": [{
+ "name": "spring-cloud-kubernetes-client-discovery",
+ "env": [
+ {
+ "name": "LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_COMMONS_DISCOVERY",
+ "value": "DEBUG"
+ },
+ {
+ "name": "LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_CLIENT_DISCOVERY_HEALTH_REACTIVE",
+ "value": "DEBUG"
+ },
+ {
+ "name": "LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT_DISCOVERY_REACTIVE",
+ "value": "DEBUG"
+ },
+ {
+ "name": "LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT_DISCOVERY",
+ "value": "DEBUG"
+ },
+ {
+ "name": "SPRING_CLOUD_DISCOVERY_BLOCKING_ENABLED",
+ "value": "FALSE"
+ },
+ {
+ "name": "SPRING_CLOUD_DISCOVERY_REACTIVE_ENABLED",
+ "value": "TRUE"
+ }
+ ]
+ }]
+ }
+ }
+ }
+ }
+ """;
+
+ // this one patches on top of BODY_TWO, so it essentially enables both blocking and
+ // reactive implementations
+ // and adds proper packages in DEBUG mode, so that we could assert logs.
+ private static final String BODY_THREE = """
+ {
+ "spec": {
+ "template": {
+ "spec": {
+ "containers": [{
+ "name": "spring-cloud-kubernetes-client-discovery",
+ "env": [{
+ "name": "SPRING_CLOUD_DISCOVERY_BLOCKING_ENABLED",
+ "value": "TRUE"
+ }]
+ }]
+ }
+ }
+ }
+ }
+ """;
+
+ // this one patches on top of BODY_TWO, so it essentially enables both blocking and
+ // reactive implementations
+ // and adds proper packages in DEBUG mode, so that we could assert logs.
+ private static final String BODY_FOUR = """
+ {
+ "spec": {
+ "template": {
+ "spec": {
+ "containers": [{
+ "name": "spring-cloud-kubernetes-client-discovery",
+ "image": "image_name_here",
+ "env": [
+ {
+ "name": "LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_COMMONS_DISCOVERY",
+ "value": "DEBUG"
+ },
+ {
+ "name": "SPRING_CLOUD_DISCOVERY_REACTIVE_ENABLED",
+ "value": "FALSE"
+ },
+ {
+ "name": "LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_CLIENT_DISCOVERY_HEALTH",
+ "value": "DEBUG"
+ },
+ {
+ "name": "LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT_DISCOVERY",
+ "value": "DEBUG"
+ }
+ ]
+ }]
+ }
+ }
+ }
+ }
+ """;
+
+ // patch to include all namespaces
+ private static final String BODY_FIVE = """
+ {
+ "spec": {
+ "template": {
+ "spec": {
+ "containers": [{
+ "name": "spring-cloud-kubernetes-client-discovery",
+ "env": [{
+ "name": "SPRING_CLOUD_KUBERNETES_DISCOVERY_ALL_NAMESPACES",
+ "value": "TRUE"
+ }]
+ }]
+ }
+ }
+ }
+ }
+ """;
+
+ // disable all namespaces and include a single namespace to be discoverable
+ private static final String BODY_SIX = """
+ {
+ "spec": {
+ "template": {
+ "spec": {
+ "containers": [{
+ "name": "spring-cloud-kubernetes-client-discovery",
+ "env": [
+ {
+ "name": "SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0",
+ "value": "a"
+ },
+ {
+ "name": "SPRING_CLOUD_KUBERNETES_DISCOVERY_ALL_NAMESPACES",
+ "value": "FALSE"
+ }
+ ]
+ }]
+ }
+ }
+ }
+ }
+ """;
+
+ private static final String BODY_SEVEN = """
+ {
+ "spec": {
+ "template": {
+ "spec": {
+ "containers": [{
+ "name": "spring-cloud-kubernetes-client-discovery",
+ "image": "image_name_here",
+ "env": [
+ {
+ "name": "LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT_DISCOVERY",
+ "value": "DEBUG"
+ },
+ {
+ "name": "SPRING_CLOUD_KUBERNETES_DISCOVERY_METADATA_ADDLABELS",
+ "value": "TRUE"
+ },
+ {
+ "name": "SPRING_CLOUD_KUBERNETES_DISCOVERY_METADATA_LABELSPREFIX",
+ "value": "label-"
+ },
+ {
+ "name": "SPRING_CLOUD_KUBERNETES_DISCOVERY_METADATA_ADDANNOTATIONS",
+ "value": "TRUE"
+ },
+ {
+ "name": "SPRING_CLOUD_KUBERNETES_DISCOVERY_METADATA_ANNOTATIONSPREFIX",
+ "value": "annotation-"
+ }
+ ]
+ }]
+ }
+ }
+ }
+ }
+ """;
+
+ private static final String BODY_EIGHT = """
+ {
+ "spec": {
+ "template": {
+ "spec": {
+ "containers": [{
+ "name": "spring-cloud-kubernetes-client-discovery",
+ "env": [
+ {
+ "name": "SPRING_CLOUD_DISCOVERY_REACTIVE_ENABLED",
+ "value": "TRUE"
+ },
+ {
+ "name": "SPRING_CLOUD_DISCOVERY_BLOCKING_ENABLED",
+ "value": "FALSE"
+ }
+ ]
+ }]
+ }
+ }
+ }
+ }
+ """;
+
+ private static final String BODY_NINE = """
+ {
+ "spec": {
+ "template": {
+ "spec": {
+ "containers": [{
+ "name": "spring-cloud-kubernetes-client-discovery",
+ "env": [
+ {
+ "name": "SPRING_CLOUD_DISCOVERY_REACTIVE_ENABLED",
+ "value": "TRUE"
+ },
+ {
+ "name": "SPRING_CLOUD_DISCOVERY_BLOCKING_ENABLED",
+ "value": "TRUE"
+ }
+ ]
+ }]
+ }
+ }
+ }
+ }
+ """;
+
+ private static final String BODY_TEN = """
+ {
+ "spec": {
+ "template": {
+ "spec": {
+ "containers": [{
+ "name": "spring-cloud-kubernetes-client-discovery",
+ "env": [
+ {
+ "name": "SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_1",
+ "value": "b"
+ },
+ {
+ "name": "SPRING_CLOUD_DISCOVERY_REACTIVE_ENABLED",
+ "value": "FALSE"
+ }
+ ]
+ }]
+ }
+ }
+ }
+ }
+ """;
+
+ private static final String BODY_ELEVEN = """
+ {
+ "spec": {
+ "template": {
+ "spec": {
+ "containers": [{
+ "name": "spring-cloud-kubernetes-client-discovery",
+ "env": [
+ {
+ "name": "SPRING_CLOUD_DISCOVERY_BLOCKING_ENABLED",
+ "value": "TRUE"
+ }
+ ]
+ }]
+ }
+ }
+ }
+ }
+ """;
+
+ private static final String BODY_TWELVE = """
+ {
+ "spec": {
+ "template": {
+ "spec": {
+ "containers": [{
+ "name": "spring-cloud-kubernetes-client-discovery",
+ "image": "image_name_here",
+ "env": [
+ {
+ "name": "SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0",
+ "value": "a-uat"
+ },
+ {
+ "name": "SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_1",
+ "value": "b-uat"
+ },
+ {
+ "name": "SPRING_CLOUD_KUBERNETES_DISCOVERY_FILTER",
+ "value": "#root.metadata.namespace matches 'a-uat$'"
+ },
+ {
+ "name": "LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT_DISCOVERY",
+ "value": "DEBUG"
+ }
+ ]
+ }]
+ }
+ }
+ }
+ }
+ """;
+
+ private KubernetesClientDiscoveryClientUtils() {
+
+ }
+
+ static void patchForTwoNamespacesMatchViaThePredicate(String deploymentName, String namespace) {
+ patchWithMerge(deploymentName, namespace, BODY_ONE);
+ }
+
+ static void patchForReactiveHealth(String deploymentName, String namespace) {
+ patchWithMerge(deploymentName, namespace, BODY_TWO);
+ }
+
+ static void patchForBlockingAndReactiveHealth(String deploymentName, String namespace) {
+ patchWithMerge(deploymentName, namespace, BODY_THREE);
+ }
+
+ // notice the usage of 'PATCH_FORMAT_JSON_MERGE_PATCH' here, it will not merge
+ // env variables
+ static void patchForBlockingHealth(String image, String deploymentName, String namespace) {
+ patchWithReplace(image, deploymentName, namespace, BODY_FOUR);
+ }
+
+ // add SPRING_CLOUD_KUBERNETES_DISCOVERY_ALL_NAMESPACES=TRUE
+ static void patchForAllNamespaces(String deploymentName, String namespace) {
+ patchWithMerge(deploymentName, namespace, BODY_FIVE);
+ }
+
+ static void patchForSingleNamespace(String deploymentName, String namespace) {
+ patchWithMerge(deploymentName, namespace, BODY_SIX);
+ }
+
+ static void patchForPodMetadata(String imageName, String deploymentName, String namespace) {
+ patchWithReplace(imageName, deploymentName, namespace, BODY_SEVEN);
+ }
+
+ static void patchForReactiveOnly(String deploymentName, String namespace) {
+ patchWithMerge(deploymentName, namespace, BODY_EIGHT);
+ }
+
+ static void patchForBlockingAndReactive(String deploymentName, String namespace) {
+ patchWithMerge(deploymentName, namespace, BODY_NINE);
+ }
+
+ static void patchForTwoNamespacesBlockingOnly(String deploymentName, String namespace) {
+ patchWithMerge(deploymentName, namespace, BODY_TEN);
+ }
+
+ static void patchToAddBlockingSupport(String deploymentName, String namespace) {
+ patchWithMerge(deploymentName, namespace, BODY_ELEVEN);
+ }
+
+ static void patchForUATNamespacesTests(String image, String deploymentName, String namespace) {
+ patchWithReplace(image, deploymentName, namespace, BODY_TWELVE);
+ }
+
+ private static void patchWithMerge(String deploymentName, String namespace, String patchBody) {
+ try {
+ PatchUtils.patch(V1Deployment.class,
+ () -> new AppsV1Api().patchNamespacedDeploymentCall(deploymentName, namespace,
+ new V1Patch(patchBody), null, null, null, null, null, null),
+ V1Patch.PATCH_FORMAT_STRATEGIC_MERGE_PATCH, new CoreV1Api().getApiClient());
+ }
+ catch (ApiException e) {
+ LOG.error(() -> "error : " + e.getResponseBody());
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static void patchWithReplace(String imageName, String deploymentName, String namespace, String patchBody) {
+ String body = patchBody.replace("image_name_here", imageName);
+
+ try {
+ PatchUtils.patch(V1Deployment.class,
+ () -> new AppsV1Api().patchNamespacedDeploymentCall(deploymentName, namespace, new V1Patch(body),
+ null, null, null, null, null, null),
+ V1Patch.PATCH_FORMAT_JSON_MERGE_PATCH, new CoreV1Api().getApiClient());
+ }
+ catch (ApiException e) {
+ LOG.error(() -> "error : " + e.getResponseBody());
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryFilterIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryFilterITDelegate.java
similarity index 60%
rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryFilterIT.java
rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryFilterITDelegate.java
index 93c27a57..3fafb389 100644
--- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryFilterIT.java
+++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryFilterITDelegate.java
@@ -17,31 +17,18 @@
package org.springframework.cloud.kubernetes.client.discovery.it;
import java.time.Duration;
-import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.Optional;
import java.util.Set;
-import io.kubernetes.client.openapi.models.V1Deployment;
-import io.kubernetes.client.openapi.models.V1EnvVar;
-import io.kubernetes.client.openapi.models.V1Ingress;
-import io.kubernetes.client.openapi.models.V1Service;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.BeforeEach;
-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.cloud.kubernetes.commons.discovery.DefaultKubernetesServiceInstance;
-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 org.springframework.core.ParameterizedTypeReference;
@@ -52,11 +39,7 @@ import org.springframework.web.reactive.function.client.WebClient;
/**
* @author wind57
*/
-class KubernetesClientDiscoveryFilterIT {
-
- private static final String FILTER_BOTH_NAMESPACES = "#root.metadata.namespace matches '^.*uat$'";
-
- private static final String FILTER_SINGLE_NAMESPACE = "#root.metadata.namespace matches 'a-uat$'";
+class KubernetesClientDiscoveryFilterITDelegate {
private static final String NAMESPACE_A_UAT = "a-uat";
@@ -64,42 +47,42 @@ class KubernetesClientDiscoveryFilterIT {
private static final String NAMESPACE = "default";
- private static final String IMAGE_NAME = "spring-cloud-kubernetes-client-discovery-it";
+ private static final String DEPLOYMENT_NAME = "spring-cloud-kubernetes-client-discovery-deployment-it";
- private static Util util;
+ void filterMatchesOneNamespaceViaThePredicate(Util util) {
- private static final K3sContainer K3S = Commons.container();
-
- @BeforeAll
- static void beforeAll() throws Exception {
- K3S.start();
- Commons.validateImage(IMAGE_NAME, K3S);
- Commons.loadSpringCloudKubernetesImage(IMAGE_NAME, K3S);
-
- util = new Util(K3S);
- Commons.systemPrune();
- }
-
- @BeforeEach
- void beforeEach() {
+ // set-up for this test and the next one
util.createNamespace(NAMESPACE_A_UAT);
util.createNamespace(NAMESPACE_B_UAT);
util.setUpClusterWide(NAMESPACE, Set.of(NAMESPACE, NAMESPACE_A_UAT, NAMESPACE_B_UAT));
util.wiremock(NAMESPACE_A_UAT, "/wiremock", Phase.CREATE);
util.wiremock(NAMESPACE_B_UAT, "/wiremock", Phase.CREATE);
- }
- @AfterEach
- void afterEach() {
- util.wiremock(NAMESPACE_A_UAT, "/wiremock", Phase.DELETE);
- util.wiremock(NAMESPACE_B_UAT, "/wiremock", Phase.DELETE);
- util.deleteNamespace(NAMESPACE_A_UAT);
- util.deleteNamespace(NAMESPACE_B_UAT);
- }
+ WebClient clientServices = builder().baseUrl("http://localhost/services").build();
+
+ @SuppressWarnings("unchecked")
+ List services = (List) clientServices.method(HttpMethod.GET).retrieve().bodyToMono(List.class)
+ .retryWhen(retrySpec()).block();
+
+ Assertions.assertEquals(services.size(), 1);
+ Assertions.assertTrue(services.contains("service-wiremock"));
+
+ WebClient client = builder().baseUrl("http://localhost/service-instances/service-wiremock").build();
+ List serviceInstances = client.method(HttpMethod.GET).retrieve()
+ .bodyToMono(new ParameterizedTypeReference>() {
+
+ }).retryWhen(retrySpec()).block();
+
+ Assertions.assertEquals(serviceInstances.size(), 1);
+
+ DefaultKubernetesServiceInstance first = serviceInstances.get(0);
+ Assertions.assertEquals(first.getServiceId(), "service-wiremock");
+ Assertions.assertNotNull(first.getInstanceId());
+ Assertions.assertEquals(first.getPort(), 8080);
+ Assertions.assertEquals(first.getNamespace(), "a-uat");
+ Assertions.assertEquals(first.getMetadata(),
+ Map.of("app", "service-wiremock", "http", "8080", "k8s_namespace", "a-uat", "type", "ClusterIP"));
- @AfterAll
- static void after() throws Exception {
- Commons.cleanUp(IMAGE_NAME, K3S);
}
/**
@@ -112,10 +95,12 @@ class KubernetesClientDiscoveryFilterIT {
* As such, both services are found via 'getInstances' call.
*
*/
- @Test
- void filterMatchesBothNamespacesViaThePredicate() {
+ void filterMatchesBothNamespacesViaThePredicate(Util util) {
- manifests(Phase.CREATE, FILTER_BOTH_NAMESPACES);
+ // patch the deployment to change what namespaces are take into account
+ KubernetesClientDiscoveryClientUtils.patchForTwoNamespacesMatchViaThePredicate(DEPLOYMENT_NAME, NAMESPACE);
+ util.waitForDeploymentAfterPatch(DEPLOYMENT_NAME, NAMESPACE,
+ Map.of("app", "spring-cloud-kubernetes-client-discovery-it"));
WebClient clientServices = builder().baseUrl("http://localhost/services").build();
@@ -152,80 +137,6 @@ class KubernetesClientDiscoveryFilterIT {
Assertions.assertEquals(second.getMetadata(),
Map.of("app", "service-wiremock", "http", "8080", "k8s_namespace", "b-uat", "type", "ClusterIP"));
- manifests(Phase.DELETE, FILTER_BOTH_NAMESPACES);
- }
-
- /**
- *
- * - service "wiremock" is present in namespace "a-uat"
- * - service "wiremock" is present in namespace "b-uat"
- *
- * - we search with a predicate : "#root.metadata.namespace matches 'a-uat$'"
- *
- * As such, only service from 'a-uat' namespace matches.
- *
- */
- @Test
- void filterMatchesOneNamespaceViaThePredicate() {
- manifests(Phase.CREATE, FILTER_SINGLE_NAMESPACE);
-
- WebClient clientServices = builder().baseUrl("http://localhost/services").build();
-
- @SuppressWarnings("unchecked")
- List services = (List) clientServices.method(HttpMethod.GET).retrieve().bodyToMono(List.class)
- .retryWhen(retrySpec()).block();
-
- Assertions.assertEquals(services.size(), 1);
- Assertions.assertTrue(services.contains("service-wiremock"));
-
- WebClient client = builder().baseUrl("http://localhost/service-instances/service-wiremock").build();
- List serviceInstances = client.method(HttpMethod.GET).retrieve()
- .bodyToMono(new ParameterizedTypeReference>() {
-
- }).retryWhen(retrySpec()).block();
-
- Assertions.assertEquals(serviceInstances.size(), 1);
-
- DefaultKubernetesServiceInstance first = serviceInstances.get(0);
- Assertions.assertEquals(first.getServiceId(), "service-wiremock");
- Assertions.assertNotNull(first.getInstanceId());
- Assertions.assertEquals(first.getPort(), 8080);
- Assertions.assertEquals(first.getNamespace(), "a-uat");
- Assertions.assertEquals(first.getMetadata(),
- Map.of("app", "service-wiremock", "http", "8080", "k8s_namespace", "a-uat", "type", "ClusterIP"));
-
- manifests(Phase.DELETE, FILTER_SINGLE_NAMESPACE);
- }
-
- private static void manifests(Phase phase, String serviceFilter) {
-
- V1Deployment deployment = (V1Deployment) util.yaml("kubernetes-discovery-deployment.yaml");
- V1Service service = (V1Service) util.yaml("kubernetes-discovery-service.yaml");
- V1Ingress ingress = (V1Ingress) util.yaml("kubernetes-discovery-ingress.yaml");
-
- List envVars = new ArrayList<>(
- Optional.ofNullable(deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv())
- .orElse(List.of()));
- V1EnvVar namespaceAUat = new V1EnvVar().name("SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0")
- .value(NAMESPACE_A_UAT);
- V1EnvVar namespaceBUat = new V1EnvVar().name("SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_1")
- .value(NAMESPACE_B_UAT);
- V1EnvVar filter = new V1EnvVar().name("SPRING_CLOUD_KUBERNETES_DISCOVERY_FILTER").value(serviceFilter);
- V1EnvVar debug = new V1EnvVar().name("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT_DISCOVERY")
- .value("DEBUG");
- envVars.add(namespaceAUat);
- envVars.add(namespaceBUat);
- envVars.add(filter);
- envVars.add(debug);
- deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(envVars);
-
- if (phase.equals(Phase.CREATE)) {
- util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
- }
- else if (phase.equals(Phase.DELETE)) {
- util.deleteAndWait(NAMESPACE, deployment, service, ingress);
- }
-
}
private WebClient.Builder builder() {
diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryHealthIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryHealthITDelegate.java
similarity index 59%
rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryHealthIT.java
rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryHealthITDelegate.java
index 13adeafa..8c46e2bb 100644
--- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryHealthIT.java
+++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryHealthITDelegate.java
@@ -17,19 +17,12 @@
package org.springframework.cloud.kubernetes.client.discovery.it;
import java.time.Duration;
-import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
-import java.util.Optional;
+import java.util.concurrent.TimeUnit;
-import io.kubernetes.client.openapi.models.V1Deployment;
-import io.kubernetes.client.openapi.models.V1EnvVar;
-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.containers.Container;
import org.testcontainers.k3s.K3sContainer;
import reactor.netty.http.client.HttpClient;
@@ -37,18 +30,18 @@ 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.Phase;
import org.springframework.cloud.kubernetes.integration.tests.commons.native_client.Util;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;
+import static org.awaitility.Awaitility.await;
+
/**
* @author wind57
*/
-class KubernetesClientDiscoveryHealthIT {
+class KubernetesClientDiscoveryHealthITDelegate {
private static final String REACTIVE_STATUS = "$.components.reactiveDiscoveryClients.components.['Kubernetes Reactive Discovery Client'].status";
@@ -58,28 +51,10 @@ class KubernetesClientDiscoveryHealthIT {
private static final String IMAGE_NAME = "spring-cloud-kubernetes-client-discovery-it";
+ private static final String DEPLOYMENT_NAME = "spring-cloud-kubernetes-client-discovery-deployment-it";
+
private static final BasicJsonTester BASIC_JSON_TESTER = new BasicJsonTester(
- KubernetesClientDiscoveryHealthIT.class);
-
- private static Util util;
-
- private static final K3sContainer K3S = Commons.container();
-
- @BeforeAll
- static void beforeAll() throws Exception {
- K3S.start();
- Commons.validateImage(IMAGE_NAME, K3S);
- Commons.loadSpringCloudKubernetesImage(IMAGE_NAME, K3S);
-
- util = new Util(K3S);
- Commons.systemPrune();
- util.setUp(NAMESPACE);
- }
-
- @AfterAll
- static void after() throws Exception {
- Commons.cleanUp(IMAGE_NAME, K3S);
- }
+ KubernetesClientDiscoveryHealthITDelegate.class);
/**
* Reactive is disabled, only blocking is active. As such,
@@ -89,15 +64,12 @@ class KubernetesClientDiscoveryHealthIT {
* We assert for logs and call '/health' endpoint to see that blocking discovery
* client was initialized.
*/
- @Test
- void testBlockingConfiguration() {
+ void testBlockingConfiguration(K3sContainer container) {
- manifests(true, false, Phase.CREATE);
-
- assertLogStatement("Will publish InstanceRegisteredEvent from blocking implementation");
- assertLogStatement("publishing InstanceRegisteredEvent");
- assertLogStatement("Discovery Client has been initialized");
- assertLogStatement(
+ assertLogStatement(container, "Will publish InstanceRegisteredEvent from blocking implementation");
+ assertLogStatement(container, "publishing InstanceRegisteredEvent");
+ assertLogStatement(container, "Discovery Client has been initialized");
+ assertLogStatement(container,
"received InstanceRegisteredEvent from pod with 'app' label value : spring-cloud-kubernetes-client-discovery-it");
WebClient healthClient = builder().baseUrl("http://localhost/actuator/health").build();
@@ -118,52 +90,6 @@ class KubernetesClientDiscoveryHealthIT {
Assertions.assertThat(BASIC_JSON_TESTER.from(healthResult)).doesNotHaveJsonPath(REACTIVE_STATUS);
- manifests(true, false, Phase.DELETE);
- }
-
- /**
- * Both blocking and reactive are enabled.
- */
- @Test
- void testDefaultConfiguration() {
-
- manifests(false, false, Phase.CREATE);
-
- assertLogStatement("Will publish InstanceRegisteredEvent from blocking implementation");
- assertLogStatement("publishing InstanceRegisteredEvent");
- assertLogStatement("Discovery Client has been initialized");
- assertLogStatement(
- "received InstanceRegisteredEvent from pod with 'app' label value : spring-cloud-kubernetes-client-discovery-it");
-
- WebClient healthClient = builder().baseUrl("http://localhost/actuator/health").build();
-
- String healthResult = healthClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class)
- .retryWhen(retrySpec()).block();
-
- Assertions.assertThat(BASIC_JSON_TESTER.from(healthResult))
- .extractingJsonPathStringValue("$.components.discoveryComposite.status").isEqualTo("UP");
-
- Assertions.assertThat(BASIC_JSON_TESTER.from(healthResult))
- .extractingJsonPathStringValue("$.components.discoveryComposite.components.discoveryClient.status")
- .isEqualTo("UP");
-
- Assertions.assertThat(BASIC_JSON_TESTER.from(healthResult))
- .extractingJsonPathArrayValue(
- "$.components.discoveryComposite.components.discoveryClient.details.services")
- .containsExactlyInAnyOrder("spring-cloud-kubernetes-client-discovery-it", "kubernetes");
-
- Assertions.assertThat(BASIC_JSON_TESTER.from(healthResult))
- .extractingJsonPathStringValue("$.components.reactiveDiscoveryClients.status").isEqualTo("UP");
-
- Assertions.assertThat(BASIC_JSON_TESTER.from(healthResult)).extractingJsonPathStringValue(
- "$.components.reactiveDiscoveryClients.components.['Kubernetes Reactive Discovery Client'].status")
- .isEqualTo("UP");
-
- Assertions.assertThat(BASIC_JSON_TESTER.from(healthResult)).extractingJsonPathArrayValue(
- "$.components.reactiveDiscoveryClients.components.['Kubernetes Reactive Discovery Client'].details.services")
- .containsExactlyInAnyOrder("spring-cloud-kubernetes-client-discovery-it", "kubernetes");
-
- manifests(false, false, Phase.DELETE);
}
/**
@@ -174,15 +100,16 @@ class KubernetesClientDiscoveryHealthIT {
* We assert for logs and call '/health' endpoint to see that blocking discovery
* client was initialized.
*/
- @Test
- void testReactiveConfiguration() {
+ void testReactiveConfiguration(Util util, K3sContainer container) {
- manifests(false, true, Phase.CREATE);
+ KubernetesClientDiscoveryClientUtils.patchForReactiveHealth(DEPLOYMENT_NAME, NAMESPACE);
+ util.waitForDeploymentAfterPatch(DEPLOYMENT_NAME, NAMESPACE,
+ Map.of("app", "spring-cloud-kubernetes-client-discovery-it"));
- assertLogStatement("Will publish InstanceRegisteredEvent from reactive implementation");
- assertLogStatement("publishing InstanceRegisteredEvent");
- assertLogStatement("Discovery Client has been initialized");
- assertLogStatement(
+ assertLogStatement(container, "Will publish InstanceRegisteredEvent from reactive implementation");
+ assertLogStatement(container, "publishing InstanceRegisteredEvent");
+ assertLogStatement(container, "Discovery Client has been initialized");
+ assertLogStatement(container,
"received InstanceRegisteredEvent from pod with 'app' label value : spring-cloud-kubernetes-client-discovery-it");
WebClient healthClient = builder().baseUrl("http://localhost/actuator/health").build();
@@ -213,69 +140,51 @@ class KubernetesClientDiscoveryHealthIT {
Assertions.assertThat(servicesResult).contains("spring-cloud-kubernetes-client-discovery-it");
Assertions.assertThat(servicesResult).contains("kubernetes");
- manifests(false, true, Phase.DELETE);
}
- private static void manifests(boolean disableReactive, boolean disableBlocking, Phase phase) {
- V1Deployment deployment = (V1Deployment) util.yaml("kubernetes-discovery-deployment.yaml");
- V1Service service = (V1Service) util.yaml("kubernetes-discovery-service.yaml");
- V1Ingress ingress = (V1Ingress) util.yaml("kubernetes-discovery-ingress.yaml");
+ /**
+ * Both blocking and reactive are enabled.
+ */
+ void testDefaultConfiguration(Util util, K3sContainer container) {
- List envVars = new ArrayList<>(
- Optional.ofNullable(deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv())
- .orElse(List.of()));
+ KubernetesClientDiscoveryClientUtils.patchForBlockingAndReactiveHealth(DEPLOYMENT_NAME, NAMESPACE);
+ util.waitForDeploymentAfterPatch(DEPLOYMENT_NAME, NAMESPACE,
+ Map.of("app", "spring-cloud-kubernetes-client-discovery-it"));
- V1EnvVar debugLevelForCommons = new V1EnvVar()
- .name("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_COMMONS_DISCOVERY").value("DEBUG");
+ assertLogStatement(container, "Will publish InstanceRegisteredEvent from blocking implementation");
+ assertLogStatement(container, "publishing InstanceRegisteredEvent");
+ assertLogStatement(container, "Discovery Client has been initialized");
+ assertLogStatement(container,
+ "received InstanceRegisteredEvent from pod with 'app' label value : spring-cloud-kubernetes-client-discovery-it");
- if (!disableBlocking) {
- V1EnvVar debugBlockingEnvVar = new V1EnvVar()
- .name("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_CLIENT_DISCOVERY_HEALTH").value("DEBUG");
+ WebClient healthClient = builder().baseUrl("http://localhost/actuator/health").build();
- V1EnvVar debugLevelForBlocking = new V1EnvVar()
- .name("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT_DISCOVERY").value("DEBUG");
+ String healthResult = healthClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class)
+ .retryWhen(retrySpec()).block();
- envVars.add(debugBlockingEnvVar);
- envVars.add(debugLevelForBlocking);
- }
+ Assertions.assertThat(BASIC_JSON_TESTER.from(healthResult))
+ .extractingJsonPathStringValue("$.components.discoveryComposite.status").isEqualTo("UP");
- if (!disableReactive) {
- V1EnvVar debugReactiveEnvVar = new V1EnvVar()
- .name("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_CLIENT_DISCOVERY_HEALTH_REACTIVE").value("DEBUG");
+ Assertions.assertThat(BASIC_JSON_TESTER.from(healthResult))
+ .extractingJsonPathStringValue("$.components.discoveryComposite.components.discoveryClient.status")
+ .isEqualTo("UP");
- V1EnvVar debugLevelForReactive = new V1EnvVar()
- .name("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT_DISCOVERY_REACTIVE")
- .value("DEBUG");
+ Assertions.assertThat(BASIC_JSON_TESTER.from(healthResult))
+ .extractingJsonPathArrayValue(
+ "$.components.discoveryComposite.components.discoveryClient.details.services")
+ .containsExactlyInAnyOrder("spring-cloud-kubernetes-client-discovery-it", "kubernetes");
- V1EnvVar debugLevelForBlocking = new V1EnvVar()
- .name("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT_DISCOVERY").value("DEBUG");
+ Assertions.assertThat(BASIC_JSON_TESTER.from(healthResult))
+ .extractingJsonPathStringValue("$.components.reactiveDiscoveryClients.status").isEqualTo("UP");
- envVars.add(debugReactiveEnvVar);
- envVars.add(debugLevelForBlocking);
- envVars.add(debugLevelForReactive);
- }
+ Assertions.assertThat(BASIC_JSON_TESTER.from(healthResult)).extractingJsonPathStringValue(
+ "$.components.reactiveDiscoveryClients.components.['Kubernetes Reactive Discovery Client'].status")
+ .isEqualTo("UP");
- if (disableBlocking) {
- V1EnvVar disableBlockingEnvVar = new V1EnvVar().name("SPRING_CLOUD_DISCOVERY_BLOCKING_ENABLED")
- .value("FALSE");
- envVars.add(disableBlockingEnvVar);
- }
+ Assertions.assertThat(BASIC_JSON_TESTER.from(healthResult)).extractingJsonPathArrayValue(
+ "$.components.reactiveDiscoveryClients.components.['Kubernetes Reactive Discovery Client'].details.services")
+ .containsExactlyInAnyOrder("spring-cloud-kubernetes-client-discovery-it", "kubernetes");
- if (disableReactive) {
- V1EnvVar disableReactiveEnvVar = new V1EnvVar().name("SPRING_CLOUD_DISCOVERY_REACTIVE_ENABLED")
- .value("FALSE");
- envVars.add(disableReactiveEnvVar);
- }
-
- envVars.add(debugLevelForCommons);
- deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(envVars);
-
- if (phase.equals(Phase.CREATE)) {
- util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
- }
- else if (phase.equals(Phase.DELETE)) {
- util.deleteAndWait(NAMESPACE, deployment, service, ingress);
- }
}
private WebClient.Builder builder() {
@@ -286,14 +195,18 @@ class KubernetesClientDiscoveryHealthIT {
return Retry.fixedDelay(15, Duration.ofSeconds(1)).filter(Objects::nonNull);
}
- private void assertLogStatement(String message) {
+ private void assertLogStatement(K3sContainer container, String message) {
try {
- String appPodName = K3S.execInContainer("sh", "-c",
+ String appPodName = container.execInContainer("sh", "-c",
"kubectl get pods -l app=" + IMAGE_NAME + " -o=name --no-headers | tr -d '\n'").getStdout();
- Container.ExecResult execResult = K3S.execInContainer("sh", "-c", "kubectl logs " + appPodName.trim());
- String ok = execResult.getStdout();
- Assertions.assertThat(ok).contains(message);
+ await().pollDelay(Duration.ofSeconds(4)).pollInterval(Duration.ofSeconds(1)).atMost(20, TimeUnit.SECONDS)
+ .until(() -> {
+ Container.ExecResult execResult = container.execInContainer("sh", "-c",
+ "kubectl logs " + appPodName.trim());
+ String ok = execResult.getStdout();
+ return ok.contains(message);
+ });
}
catch (Exception e) {
e.printStackTrace();
diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryMultipleSelectiveNamespacesIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryMultipleSelectiveNamespacesITDelegate.java
similarity index 67%
rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryMultipleSelectiveNamespacesIT.java
rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryMultipleSelectiveNamespacesITDelegate.java
index 328383eb..5e63e348 100644
--- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryMultipleSelectiveNamespacesIT.java
+++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryMultipleSelectiveNamespacesITDelegate.java
@@ -17,21 +17,11 @@
package org.springframework.cloud.kubernetes.client.discovery.it;
import java.time.Duration;
-import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import io.kubernetes.client.openapi.models.V1Deployment;
-import io.kubernetes.client.openapi.models.V1EnvVar;
-import io.kubernetes.client.openapi.models.V1Ingress;
-import io.kubernetes.client.openapi.models.V1Service;
-import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
import org.testcontainers.containers.Container;
import org.testcontainers.k3s.K3sContainer;
import reactor.netty.http.client.HttpClient;
@@ -39,9 +29,6 @@ import reactor.util.retry.Retry;
import reactor.util.retry.RetryBackoffSpec;
import org.springframework.cloud.kubernetes.commons.discovery.DefaultKubernetesServiceInstance;
-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 org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
@@ -50,64 +37,22 @@ import org.springframework.web.reactive.function.client.WebClient;
/**
* @author wind57
*/
-class KubernetesClientDiscoveryMultipleSelectiveNamespacesIT {
+class KubernetesClientDiscoveryMultipleSelectiveNamespacesITDelegate {
private static final String BLOCKING_PUBLISH = "Will publish InstanceRegisteredEvent from blocking implementation";
private static final String REACTIVE_PUBLISH = "Will publish InstanceRegisteredEvent from reactive implementation";
- private static final String NAMESPACE = "default";
-
- private static final String NAMESPACE_A = "a";
-
- private static final String NAMESPACE_B = "b";
-
private static final String IMAGE_NAME = "spring-cloud-kubernetes-client-discovery-it";
- private static Util util;
-
- private static final K3sContainer K3S = Commons.container();
-
- @BeforeAll
- static void beforeAll() throws Exception {
- K3S.start();
- Commons.validateImage(IMAGE_NAME, K3S);
- Commons.loadSpringCloudKubernetesImage(IMAGE_NAME, K3S);
-
- util = new Util(K3S);
- Commons.systemPrune();
-
- util.createNamespace(NAMESPACE_A);
- util.createNamespace(NAMESPACE_B);
- util.setUpClusterWide(NAMESPACE, Set.of(NAMESPACE, NAMESPACE_A, NAMESPACE_B));
- util.wiremock(NAMESPACE, "/wiremock", Phase.CREATE);
- util.wiremock(NAMESPACE_A, "/wiremock", Phase.CREATE);
- util.wiremock(NAMESPACE_B, "/wiremock", Phase.CREATE);
- }
-
- @AfterAll
- static void afterAll() throws Exception {
- Commons.cleanUp(IMAGE_NAME, K3S);
-
- util.wiremock(NAMESPACE, "/wiremock", Phase.DELETE);
- util.wiremock(NAMESPACE_A, "/wiremock", Phase.DELETE);
- util.wiremock(NAMESPACE_B, "/wiremock", Phase.DELETE);
- util.deleteClusterWide(NAMESPACE, Set.of(NAMESPACE, NAMESPACE_A, NAMESPACE_B));
- util.deleteNamespace(NAMESPACE_A);
- util.deleteNamespace(NAMESPACE_B);
- }
-
/**
* Deploy wiremock in 3 namespaces: default, a, b. Search in selective namespaces 'a'
* and 'b' with blocking enabled and reactive disabled, as such find services and it's
* instances.
*/
- @Test
- void testTwoNamespacesBlockingOnly() {
+ void testTwoNamespacesBlockingOnly(K3sContainer container) {
- manifests(Phase.CREATE, false, true);
-
- String logs = logs();
+ String logs = logs(container);
Assertions.assertTrue(logs.contains("using selective namespaces : [a, b]"));
Assertions.assertTrue(
logs.contains("ConditionalOnSelectiveNamespacesMissing : found selective namespaces : [a, b]"));
@@ -124,8 +69,6 @@ class KubernetesClientDiscoveryMultipleSelectiveNamespacesIT {
blockingCheck();
- manifests(Phase.DELETE, false, true);
-
}
/**
@@ -133,12 +76,9 @@ class KubernetesClientDiscoveryMultipleSelectiveNamespacesIT {
* and 'b' with blocking disabled and reactive enabled, as such find services and it's
* instances.
*/
- @Test
- void testTwoNamespaceReactiveOnly() {
+ void testTwoNamespaceReactiveOnly(K3sContainer container) {
- manifests(Phase.CREATE, true, false);
-
- String logs = logs();
+ String logs = logs(container);
Assertions.assertTrue(logs.contains("using selective namespaces : [a, b]"));
Assertions.assertTrue(
logs.contains("ConditionalOnSelectiveNamespacesMissing : found selective namespaces : [a, b]"));
@@ -155,8 +95,6 @@ class KubernetesClientDiscoveryMultipleSelectiveNamespacesIT {
reactiveCheck();
- manifests(Phase.DELETE, true, false);
-
}
/**
@@ -164,12 +102,9 @@ class KubernetesClientDiscoveryMultipleSelectiveNamespacesIT {
* and 'b' with blocking enabled and reactive enabled, as such find services and its
* service instances.
*/
- @Test
- void testTwoNamespacesBothBlockingAndReactive() {
+ void testTwoNamespacesBothBlockingAndReactive(K3sContainer container) {
- manifests(Phase.CREATE, false, false);
-
- String logs = logs();
+ String logs = logs(container);
Assertions.assertTrue(logs.contains("using selective namespaces : [a, b]"));
Assertions.assertTrue(
logs.contains("ConditionalOnSelectiveNamespacesMissing : found selective namespaces : [a, b]"));
@@ -187,56 +122,15 @@ class KubernetesClientDiscoveryMultipleSelectiveNamespacesIT {
blockingCheck();
reactiveCheck();
- manifests(Phase.DELETE, false, false);
-
}
- private static void manifests(Phase phase, boolean disableBlocking, boolean disableReactive) {
- V1Deployment deployment = (V1Deployment) util.yaml("kubernetes-discovery-deployment.yaml");
- V1Service service = (V1Service) util.yaml("kubernetes-discovery-service.yaml");
- V1Ingress ingress = (V1Ingress) util.yaml("kubernetes-discovery-ingress.yaml");
-
- List envVars = new ArrayList<>(
- Optional.ofNullable(deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv())
- .orElse(List.of()));
- V1EnvVar debugLevel = new V1EnvVar().name("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT_DISCOVERY")
- .value("DEBUG");
- V1EnvVar selectiveNamespaceA = new V1EnvVar().name("SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0")
- .value(NAMESPACE_A);
- V1EnvVar selectiveNamespaceB = new V1EnvVar().name("SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_1")
- .value(NAMESPACE_B);
-
- if (disableReactive) {
- V1EnvVar disableReactiveEnvVar = new V1EnvVar().name("SPRING_CLOUD_DISCOVERY_REACTIVE_ENABLED")
- .value("FALSE");
- envVars.add(disableReactiveEnvVar);
- }
-
- if (disableBlocking) {
- V1EnvVar disableBlockingEnvVar = new V1EnvVar().name("SPRING_CLOUD_DISCOVERY_BLOCKING_ENABLED")
- .value("FALSE");
- envVars.add(disableBlockingEnvVar);
- }
-
- envVars.add(debugLevel);
- envVars.add(selectiveNamespaceA);
- envVars.add(selectiveNamespaceB);
- deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(envVars);
-
- if (phase.equals(Phase.CREATE)) {
- util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
- }
- else if (phase.equals(Phase.DELETE)) {
- util.deleteAndWait(NAMESPACE, deployment, service, ingress);
- }
- }
-
- private String logs() {
+ private String logs(K3sContainer container) {
try {
- String appPodName = K3S.execInContainer("sh", "-c",
+ String appPodName = container.execInContainer("sh", "-c",
"kubectl get pods -l app=" + IMAGE_NAME + " -o=name --no-headers | tr -d '\n'").getStdout();
- Container.ExecResult execResult = K3S.execInContainer("sh", "-c", "kubectl logs " + appPodName.trim());
+ Container.ExecResult execResult = container.execInContainer("sh", "-c",
+ "kubectl logs " + appPodName.trim());
return execResult.getStdout();
}
catch (Exception e) {
diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryPodMetadataIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryPodMetadataITDelegate.java
similarity index 51%
rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryPodMetadataIT.java
rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryPodMetadataITDelegate.java
index bdfaccaa..5bfebc47 100644
--- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryPodMetadataIT.java
+++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoveryPodMetadataITDelegate.java
@@ -17,31 +17,16 @@
package org.springframework.cloud.kubernetes.client.discovery.it;
import java.time.Duration;
-import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.Optional;
-import io.kubernetes.client.openapi.models.V1Deployment;
-import io.kubernetes.client.openapi.models.V1EnvVar;
-import io.kubernetes.client.openapi.models.V1Ingress;
-import io.kubernetes.client.openapi.models.V1Service;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.BeforeEach;
-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.cloud.kubernetes.commons.discovery.DefaultKubernetesServiceInstance;
-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 org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
@@ -50,47 +35,12 @@ import org.springframework.web.reactive.function.client.WebClient;
/**
* @author wind57
*/
-class KubernetesClientDiscoveryPodMetadataIT {
-
- private static final String NAMESPACE = "default";
-
- private static final String IMAGE_NAME = "spring-cloud-kubernetes-client-discovery-it";
-
- private static Util util;
-
- private static final K3sContainer K3S = Commons.container();
-
- @BeforeAll
- static void beforeAll() throws Exception {
- K3S.start();
- Commons.validateImage(IMAGE_NAME, K3S);
- Commons.loadSpringCloudKubernetesImage(IMAGE_NAME, K3S);
-
- util = new Util(K3S);
- Commons.systemPrune();
- }
-
- @AfterAll
- static void after() throws Exception {
- Commons.cleanUp(IMAGE_NAME, K3S);
- }
-
- @BeforeEach
- void beforeEach() {
- util.setUp(NAMESPACE);
- manifests(Phase.CREATE);
- }
-
- @AfterEach
- void afterEach() {
- manifests(Phase.DELETE);
- }
+class KubernetesClientDiscoveryPodMetadataITDelegate {
/**
* Three services are deployed in the default namespace. We do not configure any
* explicit namespace and 'default' must be picked-up.
*/
- @Test
void testSimple() {
WebClient servicesClient = builder().baseUrl("http://localhost/services").build();
@@ -126,40 +76,6 @@ class KubernetesClientDiscoveryPodMetadataIT {
}
- private static void manifests(Phase phase) {
- V1Deployment deployment = (V1Deployment) util.yaml("kubernetes-discovery-deployment.yaml");
- V1Service service = (V1Service) util.yaml("kubernetes-discovery-service.yaml");
- V1Ingress ingress = (V1Ingress) util.yaml("kubernetes-discovery-ingress.yaml");
-
- List envVars = new ArrayList<>(
- Optional.ofNullable(deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv())
- .orElse(List.of()));
- V1EnvVar debugLevel = new V1EnvVar().name("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT_DISCOVERY")
- .value("DEBUG");
- V1EnvVar includeLabelMetadata = new V1EnvVar().name("SPRING_CLOUD_KUBERNETES_DISCOVERY_METADATA_ADDLABELS")
- .value("TRUE");
- V1EnvVar includeLabelMetadataPrefix = new V1EnvVar()
- .name("SPRING_CLOUD_KUBERNETES_DISCOVERY_METADATA_LABELSPREFIX").value("label-");
- V1EnvVar includeAnnotationsMetadata = new V1EnvVar()
- .name("SPRING_CLOUD_KUBERNETES_DISCOVERY_METADATA_ADDANNOTATIONS").value("TRUE");
- V1EnvVar includeAnnotationsMetadataPrefix = new V1EnvVar()
- .name("SPRING_CLOUD_KUBERNETES_DISCOVERY_METADATA_ANNOTATIONSPREFIX").value("annotation-");
-
- envVars.add(debugLevel);
- envVars.add(includeLabelMetadata);
- envVars.add(includeLabelMetadataPrefix);
- envVars.add(includeAnnotationsMetadata);
- envVars.add(includeAnnotationsMetadataPrefix);
- deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(envVars);
-
- if (phase.equals(Phase.CREATE)) {
- util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
- }
- else if (phase.equals(Phase.DELETE)) {
- util.deleteAndWait(NAMESPACE, deployment, service, ingress);
- }
- }
-
private WebClient.Builder builder() {
return WebClient.builder().clientConnector(new ReactorClientHttpConnector(HttpClient.create()));
}
diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoverySingleSelectiveNamespaceIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoverySelectiveNamespacesIT.java
similarity index 70%
rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoverySingleSelectiveNamespaceIT.java
rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoverySelectiveNamespacesIT.java
index 458b204f..f6e8f021 100644
--- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoverySingleSelectiveNamespaceIT.java
+++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/java/org/springframework/cloud/kubernetes/client/discovery/it/KubernetesClientDiscoverySelectiveNamespacesIT.java
@@ -19,6 +19,7 @@ package org.springframework.cloud.kubernetes.client.discovery.it;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
@@ -30,7 +31,10 @@ import io.kubernetes.client.openapi.models.V1Service;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
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.testcontainers.containers.Container;
import org.testcontainers.k3s.K3sContainer;
import reactor.netty.http.client.HttpClient;
@@ -49,7 +53,8 @@ import org.springframework.web.reactive.function.client.WebClient;
/**
* @author wind57
*/
-class KubernetesClientDiscoverySingleSelectiveNamespaceIT {
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+class KubernetesClientDiscoverySelectiveNamespacesIT {
private static final String BLOCKING_PUBLISH = "Will publish InstanceRegisteredEvent from blocking implementation";
@@ -63,6 +68,8 @@ class KubernetesClientDiscoverySingleSelectiveNamespaceIT {
private static final String IMAGE_NAME = "spring-cloud-kubernetes-client-discovery-it";
+ private static final String DEPLOYMENT_NAME = "spring-cloud-kubernetes-client-discovery-deployment-it";
+
private static Util util;
private static final K3sContainer K3S = Commons.container();
@@ -74,7 +81,6 @@ class KubernetesClientDiscoverySingleSelectiveNamespaceIT {
Commons.loadSpringCloudKubernetesImage(IMAGE_NAME, K3S);
util = new Util(K3S);
- Commons.systemPrune();
util.createNamespace(NAMESPACE_A);
util.createNamespace(NAMESPACE_B);
@@ -82,10 +88,11 @@ class KubernetesClientDiscoverySingleSelectiveNamespaceIT {
util.wiremock(NAMESPACE, "/wiremock", Phase.CREATE);
util.wiremock(NAMESPACE_A, "/wiremock", Phase.CREATE);
util.wiremock(NAMESPACE_B, "/wiremock", Phase.CREATE);
+ manifests(Phase.CREATE);
}
@AfterAll
- static void after() throws Exception {
+ static void afterAll() throws Exception {
Commons.cleanUp(IMAGE_NAME, K3S);
util.wiremock(NAMESPACE, "/wiremock", Phase.DELETE);
@@ -94,6 +101,7 @@ class KubernetesClientDiscoverySingleSelectiveNamespaceIT {
util.deleteClusterWide(NAMESPACE, Set.of(NAMESPACE, NAMESPACE_A, NAMESPACE_B));
util.deleteNamespace(NAMESPACE_A);
util.deleteNamespace(NAMESPACE_B);
+ manifests(Phase.DELETE);
}
/**
@@ -102,10 +110,9 @@ class KubernetesClientDiscoverySingleSelectiveNamespaceIT {
* its service instance.
*/
@Test
+ @Order(1)
void testOneNamespaceBlockingOnly() {
- manifests(Phase.CREATE, false, true);
-
String logs = logs();
Assertions.assertTrue(logs.contains("using selective namespaces : [a]"));
Assertions.assertTrue(
@@ -121,8 +128,6 @@ class KubernetesClientDiscoverySingleSelectiveNamespaceIT {
blockingCheck();
- manifests(Phase.DELETE, false, true);
-
}
/**
@@ -131,9 +136,12 @@ class KubernetesClientDiscoverySingleSelectiveNamespaceIT {
* its service instance.
*/
@Test
+ @Order(2)
void testOneNamespaceReactiveOnly() {
- manifests(Phase.CREATE, true, false);
+ KubernetesClientDiscoveryClientUtils.patchForReactiveOnly(DEPLOYMENT_NAME, NAMESPACE);
+ util.waitForDeploymentAfterPatch(DEPLOYMENT_NAME, NAMESPACE,
+ Map.of("app", "spring-cloud-kubernetes-client-discovery-it"));
String logs = logs();
Assertions.assertTrue(logs.contains("using selective namespaces : [a]"));
@@ -150,8 +158,6 @@ class KubernetesClientDiscoverySingleSelectiveNamespaceIT {
reactiveCheck();
- manifests(Phase.DELETE, true, false);
-
}
/**
@@ -160,9 +166,12 @@ class KubernetesClientDiscoverySingleSelectiveNamespaceIT {
* its service instance.
*/
@Test
+ @Order(3)
void testOneNamespaceBothBlockingAndReactive() {
- manifests(Phase.CREATE, false, false);
+ KubernetesClientDiscoveryClientUtils.patchForBlockingAndReactive(DEPLOYMENT_NAME, NAMESPACE);
+ util.waitForDeploymentAfterPatch(DEPLOYMENT_NAME, NAMESPACE,
+ Map.of("app", "spring-cloud-kubernetes-client-discovery-it"));
String logs = logs();
Assertions.assertTrue(logs.contains("using selective namespaces : [a]"));
@@ -180,44 +189,101 @@ class KubernetesClientDiscoverySingleSelectiveNamespaceIT {
blockingCheck();
reactiveCheck();
- manifests(Phase.DELETE, false, false);
-
}
- private static void manifests(Phase phase, boolean disableBlocking, boolean disableReactive) {
+ /**
+ * previous test already has:
+ * - SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0 = a
+ * - SPRING_CLOUD_DISCOVERY_REACTIVE_ENABLED = TRUE
+ * - SPRING_CLOUD_DISCOVERY_BLOCKING_ENABLED = TRUE
+ *
+ * All we need to patch for is:
+ * - add one more namespace to track, via SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_1 = b
+ * - disable reactive, via SPRING_CLOUD_DISCOVERY_REACTIVE_ENABLED = FALSE
+ *
+ * As such, two namespaces + blocking only, is achieved.
+ *
+ */
+ @Test
+ @Order(4)
+ void testTwoNamespacesBlockingOnly() {
+ KubernetesClientDiscoveryClientUtils.patchForTwoNamespacesBlockingOnly(DEPLOYMENT_NAME, NAMESPACE);
+ util.waitForDeploymentAfterPatch(DEPLOYMENT_NAME, NAMESPACE,
+ Map.of("app", "spring-cloud-kubernetes-client-discovery-it"));
+ new KubernetesClientDiscoveryMultipleSelectiveNamespacesITDelegate().testTwoNamespacesBlockingOnly(K3S);
+ }
+
+ /**
+ * previous test already has:
+ * - SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0 = a
+ * - SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_1 = b
+ * - SPRING_CLOUD_DISCOVERY_REACTIVE_ENABLED = FALSE
+ * - SPRING_CLOUD_DISCOVERY_BLOCKING_ENABLED = TRUE
+ *
+ * We invert the reactive and blocking in this test via patching.
+ *
+ * As such, two namespaces + reactive only, is achieved.
+ *
+ */
+ @Test
+ @Order(5)
+ void testTwoNamespacesReactiveOnly() {
+ KubernetesClientDiscoveryClientUtils.patchForReactiveOnly(DEPLOYMENT_NAME, NAMESPACE);
+ util.waitForDeploymentAfterPatch(DEPLOYMENT_NAME, NAMESPACE,
+ Map.of("app", "spring-cloud-kubernetes-client-discovery-it"));
+ new KubernetesClientDiscoveryMultipleSelectiveNamespacesITDelegate().testTwoNamespaceReactiveOnly(K3S);
+ }
+
+ /**
+ * previous test already has:
+ * - SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0 = a
+ * - SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_1 = b
+ * - SPRING_CLOUD_DISCOVERY_REACTIVE_ENABLED = TRUE
+ * - SPRING_CLOUD_DISCOVERY_BLOCKING_ENABLED = FALSE
+ *
+ * We invert the blocking support.
+ *
+ * As such, two namespaces + blocking and reactive, is achieved.
+ *
+ */
+ @Test
+ @Order(6)
+ void testTwoNamespacesBothBlockingAndReactive() {
+ KubernetesClientDiscoveryClientUtils.patchToAddBlockingSupport(DEPLOYMENT_NAME, NAMESPACE);
+ util.waitForDeploymentAfterPatch(DEPLOYMENT_NAME, NAMESPACE,
+ Map.of("app", "spring-cloud-kubernetes-client-discovery-it"));
+ new KubernetesClientDiscoveryMultipleSelectiveNamespacesITDelegate()
+ .testTwoNamespacesBothBlockingAndReactive(K3S);
+ }
+
+ private static void manifests(Phase phase) {
V1Deployment deployment = (V1Deployment) util.yaml("kubernetes-discovery-deployment.yaml");
V1Service service = (V1Service) util.yaml("kubernetes-discovery-service.yaml");
V1Ingress ingress = (V1Ingress) util.yaml("kubernetes-discovery-ingress.yaml");
- List envVars = new ArrayList<>(
- Optional.ofNullable(deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv())
- .orElse(List.of()));
- V1EnvVar debugLevel = new V1EnvVar().name("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT_DISCOVERY")
- .value("DEBUG");
- V1EnvVar selectiveNamespaceA = new V1EnvVar().name("SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0")
- .value(NAMESPACE_A);
- if (disableReactive) {
+ if (phase.equals(Phase.DELETE)) {
+ util.deleteAndWait(NAMESPACE, deployment, service, ingress);
+ return;
+ }
+
+ if (phase.equals(Phase.CREATE)) {
+ List envVars = new ArrayList<>(
+ Optional.ofNullable(deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv())
+ .orElse(List.of()));
+ V1EnvVar debugLevel = new V1EnvVar()
+ .name("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT_DISCOVERY").value("DEBUG");
+ V1EnvVar selectiveNamespaceA = new V1EnvVar().name("SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0")
+ .value(NAMESPACE_A);
+
V1EnvVar disableReactiveEnvVar = new V1EnvVar().name("SPRING_CLOUD_DISCOVERY_REACTIVE_ENABLED")
.value("FALSE");
envVars.add(disableReactiveEnvVar);
- }
- if (disableBlocking) {
- V1EnvVar disableBlockingEnvVar = new V1EnvVar().name("SPRING_CLOUD_DISCOVERY_BLOCKING_ENABLED")
- .value("FALSE");
- envVars.add(disableBlockingEnvVar);
- }
-
- envVars.add(debugLevel);
- envVars.add(selectiveNamespaceA);
- deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(envVars);
-
- if (phase.equals(Phase.CREATE)) {
+ envVars.add(debugLevel);
+ envVars.add(selectiveNamespaceA);
+ deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(envVars);
util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
}
- else if (phase.equals(Phase.DELETE)) {
- util.deleteAndWait(NAMESPACE, deployment, service, ingress);
- }
}
private void reactiveCheck() {
diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/resources/kubernetes-discovery-deployment.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/resources/kubernetes-discovery-deployment.yaml
index 3fe5f0a2..bb8eaa28 100644
--- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/resources/kubernetes-discovery-deployment.yaml
+++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-client-discovery-it/src/test/resources/kubernetes-discovery-deployment.yaml
@@ -20,15 +20,15 @@ spec:
httpGet:
port: 8080
path: /actuator/health/readiness
- initialDelaySeconds: 10
+ initialDelaySeconds: 15
periodSeconds: 2
- failureThreshold: 3
+ failureThreshold: 5
livenessProbe:
httpGet:
port: 8080
path: /actuator/health/liveness
- initialDelaySeconds: 10
+ initialDelaySeconds: 15
periodSeconds: 2
- failureThreshold: 3
+ failureThreshold: 5
ports:
- containerPort: 8080
diff --git a/spring-cloud-kubernetes-test-support/src/main/java/org/springframework/cloud/kubernetes/integration/tests/commons/Commons.java b/spring-cloud-kubernetes-test-support/src/main/java/org/springframework/cloud/kubernetes/integration/tests/commons/Commons.java
index 3fb9903b..dd737834 100644
--- a/spring-cloud-kubernetes-test-support/src/main/java/org/springframework/cloud/kubernetes/integration/tests/commons/Commons.java
+++ b/spring-cloud-kubernetes-test-support/src/main/java/org/springframework/cloud/kubernetes/integration/tests/commons/Commons.java
@@ -162,19 +162,6 @@ public final class Commons {
CONTAINER.execInContainer("crictl", "rmi", image);
}
- /**
- * equivalent of 'docker system prune', but for crictl.
- */
- public static void systemPrune() {
- try {
- CONTAINER.execInContainer("sh", "-c",
- "crictl ps -a | grep -v Running | awk '{print $1}' | xargs crictl rm && crictl rmi --prune");
- }
- catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
/**
* validates that the provided image does exist in the local docker registry.
*/
diff --git a/spring-cloud-kubernetes-test-support/src/main/java/org/springframework/cloud/kubernetes/integration/tests/commons/native_client/Util.java b/spring-cloud-kubernetes-test-support/src/main/java/org/springframework/cloud/kubernetes/integration/tests/commons/native_client/Util.java
index dbb0ebe8..e46aa618 100644
--- a/spring-cloud-kubernetes-test-support/src/main/java/org/springframework/cloud/kubernetes/integration/tests/commons/native_client/Util.java
+++ b/spring-cloud-kubernetes-test-support/src/main/java/org/springframework/cloud/kubernetes/integration/tests/commons/native_client/Util.java
@@ -24,6 +24,7 @@ import java.net.HttpURLConnection;
import java.time.Duration;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -135,10 +136,6 @@ public final class Util {
if (e instanceof ApiException apiException) {
System.out.println(apiException.getResponseBody());
}
- e.printStackTrace();
- LOG.info("events : " + events());
- LOG.info("describe deployment : " + describeDeployment(deployment));
- LOG.info("node events : " + nodeEvents());
throw new RuntimeException(e);
}
}
@@ -593,6 +590,46 @@ public final class Util {
return availableReplicas != null && availableReplicas >= 1;
}
+ public void waitForDeploymentAfterPatch(String deploymentName, String namespace, Map labels) {
+ try {
+ await().pollDelay(Duration.ofSeconds(4)).pollInterval(Duration.ofSeconds(3)).atMost(60, TimeUnit.SECONDS)
+ .until(() -> isDeploymentReadyAfterPatch(deploymentName, namespace, labels));
+ }
+ catch (Exception e) {
+ if (e instanceof ApiException apiException) {
+ LOG.error("Error: ");
+ LOG.error(apiException.getResponseBody());
+ }
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ private boolean isDeploymentReadyAfterPatch(String deploymentName, String namespace, Map labels)
+ throws ApiException {
+
+ V1DeploymentList deployments = appsV1Api.listNamespacedDeployment(namespace, null, null, null,
+ "metadata.name=" + deploymentName, null, null, null, null, null, null);
+ if (deployments.getItems().size() < 1) {
+ fail("No deployment with name " + deploymentName);
+ }
+
+ V1Deployment deployment = deployments.getItems().get(0);
+ // if no replicas are defined, it means only 1 is needed
+ int replicas = Optional.ofNullable(deployment.getSpec().getReplicas()).orElse(1);
+
+ int numberOfPods = coreV1Api.listNamespacedPod(namespace, null, null, null, null, labelSelector(labels), null,
+ null, null, null, null).getItems().size();
+
+ if (numberOfPods != replicas) {
+ LOG.info("number of pods not yet stabilized");
+ return false;
+ }
+
+ return replicas == Optional.ofNullable(deployment.getStatus().getAvailableReplicas()).orElse(0);
+
+ }
+
private static void notExistsHandler(CheckedSupplier callee, CheckedSupplier defaulter) throws Exception {
try {
callee.get();
@@ -612,38 +649,6 @@ public final class Util {
return labels.entrySet().stream().map(en -> en.getKey() + "=" + en.getValue()).collect(Collectors.joining(","));
}
- private String events() {
- try {
- return container.execInContainer("sh", "-c", "kubectl get events").getStdout();
- }
- catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- private String nodeEvents() {
- try {
- String nodeName = container.execInContainer("sh", "-c", "kubectl get nodes --no-headers | awk '{print $1}'")
- .getStdout();
- LOG.info("nodeName : " + nodeName);
- return container.execInContainer("sh", "-c", "kubectl describe node " + nodeName).getStdout();
- }
- catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- private String describeDeployment(V1Deployment deployment) {
- try {
- return container
- .execInContainer("sh", "-c", "kubectl describe deployment " + deployment.getMetadata().getName())
- .getStdout();
- }
- catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
private interface CheckedSupplier {
T get() throws Exception;
diff --git a/spring-cloud-kubernetes-test-support/src/main/resources/wiremock/wiremock-deployment.yaml b/spring-cloud-kubernetes-test-support/src/main/resources/wiremock/wiremock-deployment.yaml
index 1799c71d..90e096cf 100644
--- a/spring-cloud-kubernetes-test-support/src/main/resources/wiremock/wiremock-deployment.yaml
+++ b/spring-cloud-kubernetes-test-support/src/main/resources/wiremock/wiremock-deployment.yaml
@@ -20,9 +20,15 @@ spec:
httpGet:
port: 8080
path: /__admin/mappings
+ initialDelaySeconds: 3
+ periodSeconds: 2
+ failureThreshold: 1
livenessProbe:
httpGet:
port: 8080
path: /__admin/mappings
+ initialDelaySeconds: 3
+ periodSeconds: 2
+ failureThreshold: 1
ports:
- containerPort: 8080