diff --git a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/it/CompositeKubernetesIntegrationTests.java b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/it/CompositeKubernetesIntegrationTests.java index 00c07893..9f1aea82 100644 --- a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/it/CompositeKubernetesIntegrationTests.java +++ b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/it/CompositeKubernetesIntegrationTests.java @@ -16,8 +16,6 @@ package org.springframework.cloud.kubernetes.configserver.it; -import java.util.ArrayList; -import java.util.List; import java.util.Map; import io.kubernetes.client.openapi.ApiException; @@ -31,10 +29,10 @@ import io.kubernetes.client.openapi.models.V1SecretBuilder; import io.kubernetes.client.openapi.models.V1SecretList; import io.kubernetes.client.openapi.models.V1SecretListBuilder; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.mockito.Mockito; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.SpyBean; @@ -42,15 +40,9 @@ import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.cloud.config.environment.Environment; import org.springframework.cloud.config.environment.PropertySource; import org.springframework.cloud.config.server.environment.NativeEnvironmentRepository; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigContext; -import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapPropertySource; import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapsCache; import org.springframework.cloud.kubernetes.commons.config.Constants; -import org.springframework.cloud.kubernetes.commons.config.NamedConfigMapNormalizedSource; -import org.springframework.cloud.kubernetes.commons.config.NormalizedSource; import org.springframework.cloud.kubernetes.configserver.KubernetesConfigServerApplication; -import org.springframework.cloud.kubernetes.configserver.KubernetesPropertySourceSupplier; -import org.springframework.core.env.MapPropertySource; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.test.context.ActiveProfiles; @@ -65,14 +57,12 @@ import static org.mockito.Mockito.when; /** * @author Arjav Dongaonkar */ -public class CompositeKubernetesIntegrationTests { - - private static final List KUBERNETES_PROPERTY_SOURCE_SUPPLIER = new ArrayList<>(); +class CompositeKubernetesIntegrationTests { private static V1ConfigMap buildConfigMap(String name, String namespace) { return new V1ConfigMapBuilder() .withMetadata( - new V1ObjectMetaBuilder().withName(name).withNamespace(namespace).withResourceVersion("1").build()) + new V1ObjectMetaBuilder().withName(name).withNamespace(namespace).build()) .addToData(Constants.APPLICATION_YAML, "dummy:\n property:\n string: \"" + name + "\"\n") .build(); } @@ -80,7 +70,7 @@ public class CompositeKubernetesIntegrationTests { private static V1Secret buildSecret(String name, String namespace) { return new V1SecretBuilder() .withMetadata( - new V1ObjectMetaBuilder().withName(name).withResourceVersion("0").withNamespace(namespace).build()) + new V1ObjectMetaBuilder().withName(name).withNamespace(namespace).build()) .addToData("password", "p455w0rd".getBytes()) .addToData("username", "user".getBytes()) .build(); @@ -93,22 +83,8 @@ public class CompositeKubernetesIntegrationTests { .addToItems(buildSecret("gateway", "default")) .build(); - @BeforeAll - public static void before() { - KUBERNETES_PROPERTY_SOURCE_SUPPLIER.add((coreApi, applicationName, namespace, springEnv) -> { - List propertySources = new ArrayList<>(); - - NormalizedSource defaultSource = new NamedConfigMapNormalizedSource(applicationName, "default", false, - true); - KubernetesClientConfigContext defaultContext = new KubernetesClientConfigContext(coreApi, defaultSource, - "default", springEnv); - propertySources.add(new KubernetesClientConfigMapPropertySource(defaultContext)); - return propertySources; - }); - } - @AfterEach - public void after() { + void after() { new KubernetesClientConfigMapsCache().discardAll(); } @@ -129,12 +105,12 @@ public class CompositeKubernetesIntegrationTests { private CoreV1Api coreV1Api; @Test - public void contextLoads() throws ApiException { - when(coreV1Api.listNamespacedConfigMap(eq("default"), eq(null), eq(null), eq(null), eq(null), eq(null), - eq(null), eq(null), eq(null), eq(null), eq(null), eq(null))) + void contextLoads() throws ApiException { + when(coreV1Api.listNamespacedConfigMap( + "default", null, null, null, null, null, null, null, null, null, null, null)) .thenReturn(CONFIGMAP_DEFAULT_LIST); - when(coreV1Api.listNamespacedSecret(eq("default"), eq(null), eq(null), eq(null), eq(null), eq(null), - eq(null), eq(null), eq(null), eq(null), eq(null), eq(null))) + when(coreV1Api.listNamespacedSecret( + "default", null, null, null, null, null, null, null, null, null, null, null)) .thenReturn(SECRET_DEFAULT_LIST); ResponseEntity response = new RestTemplate().exchange( @@ -155,7 +131,6 @@ public class CompositeKubernetesIntegrationTests { properties = { "spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.client.namespace=default", "spring.cloud.config.server.composite[0].type=kubernetes", "spring.cloud.config.server.composite[1].type=native", - "spring.cloud.config.server.composite[1].location=file:./native-config", "spring.cloud.kubernetes.secrets.enableApi=true" }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @ActiveProfiles({ "test", "composite", "kubernetes", "native" }) @@ -171,12 +146,12 @@ public class CompositeKubernetesIntegrationTests { private NativeEnvironmentRepository nativeEnvironmentRepository; @Test - public void contextLoads() throws Exception { - when(coreV1Api.listNamespacedConfigMap(eq("default"), eq(null), eq(null), eq(null), eq(null), eq(null), - eq(null), eq(null), eq(null), eq(null), eq(null), eq(null))) + void contextLoads() throws Exception { + when(coreV1Api.listNamespacedConfigMap( + "default", null, null, null, null, null, null, null, null, null, null, null)) .thenReturn(CONFIGMAP_DEFAULT_LIST); - when(coreV1Api.listNamespacedSecret(eq("default"), eq(null), eq(null), eq(null), eq(null), eq(null), - eq(null), eq(null), eq(null), eq(null), eq(null), eq(null))) + when(coreV1Api.listNamespacedSecret( + "default", null, null, null, null, null, null, null, null, null, null, null)) .thenReturn(SECRET_DEFAULT_LIST); Environment mockNativeEnvironment = new Environment("gateway", "default"); @@ -206,7 +181,6 @@ public class CompositeKubernetesIntegrationTests { properties = { "spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.client.namespace=default", "spring.cloud.config.server.composite[0].type=kubernetes", "spring.cloud.config.server.composite[1].type=native", - "spring.cloud.config.server.composite[1].location=file:./native-config", "spring.cloud.kubernetes.config.enableApi=false", "spring.cloud.kubernetes.secrets.enableApi=true" }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @@ -223,12 +197,12 @@ public class CompositeKubernetesIntegrationTests { private NativeEnvironmentRepository nativeEnvironmentRepository; @Test - public void contextLoads() throws Exception { - when(coreV1Api.listNamespacedConfigMap(eq("default"), eq(null), eq(null), eq(null), eq(null), eq(null), - eq(null), eq(null), eq(null), eq(null), eq(null), eq(null))) + void contextLoads() throws Exception { + when(coreV1Api.listNamespacedConfigMap( + "default", null, null, null, null, null, null, null, null, null, null, null)) .thenReturn(CONFIGMAP_DEFAULT_LIST); - when(coreV1Api.listNamespacedSecret(eq("default"), eq(null), eq(null), eq(null), eq(null), eq(null), - eq(null), eq(null), eq(null), eq(null), eq(null), eq(null))) + when(coreV1Api.listNamespacedSecret( + "default", null, null, null, null, null, null, null, null, null, null, null)) .thenReturn(SECRET_DEFAULT_LIST); Environment mockNativeEnvironment = new Environment("gateway", "default"); @@ -256,8 +230,7 @@ public class CompositeKubernetesIntegrationTests { @SpringBootTest(classes = { KubernetesConfigServerApplication.class }, properties = { "spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.client.namespace=default", "spring.cloud.config.server.composite[0].type=kubernetes", - "spring.cloud.config.server.composite[1].type=native", - "spring.cloud.config.server.composite[1].location=file:./native-config" }, + "spring.cloud.config.server.composite[1].type=native" }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @ActiveProfiles({ "test", "composite", "kubernetes", "native" }) class KubernetesSecretsDisabledCompositeConfigServerTest { @@ -272,12 +245,12 @@ public class CompositeKubernetesIntegrationTests { private NativeEnvironmentRepository nativeEnvironmentRepository; @Test - public void contextLoads() throws Exception { - when(coreV1Api.listNamespacedConfigMap(eq("default"), eq(null), eq(null), eq(null), eq(null), eq(null), - eq(null), eq(null), eq(null), eq(null), eq(null), eq(null))) + void contextLoads() throws Exception { + when(coreV1Api.listNamespacedConfigMap( + "default", null, null, null, null, null, null, null, null, null, null, null)) .thenReturn(CONFIGMAP_DEFAULT_LIST); - when(coreV1Api.listNamespacedSecret(eq("default"), eq(null), eq(null), eq(null), eq(null), eq(null), - eq(null), eq(null), eq(null), eq(null), eq(null), eq(null))) + when(coreV1Api.listNamespacedSecret( + "default", null, null, null, null, null, null, null, null, null, null, null)) .thenReturn(SECRET_DEFAULT_LIST); Environment mockNativeEnvironment = new Environment("gateway", "default"); @@ -306,7 +279,6 @@ public class CompositeKubernetesIntegrationTests { @SpringBootTest(classes = { KubernetesConfigServerApplication.class }, properties = { "spring.config.name:compositeconfigserver", "spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.client.namespace=default", - "spring.cloud.config.server.native.search-locations=file:./native-config", "spring.cloud.config.server.native.order=1", "spring.cloud.kubernetes.configserver.order=2", "spring.cloud.kubernetes.secrets.enableApi=true" }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @@ -323,12 +295,12 @@ public class CompositeKubernetesIntegrationTests { private NativeEnvironmentRepository nativeEnvironmentRepository; @Test - public void contextLoads() throws Exception { - when(coreV1Api.listNamespacedConfigMap(eq("default"), eq(null), eq(null), eq(null), eq(null), eq(null), - eq(null), eq(null), eq(null), eq(null), eq(null), eq(null))) + void contextLoads() throws Exception { + when(coreV1Api.listNamespacedConfigMap( + "default", null, null, null, null, null, null, null, null, null, null, null)) .thenReturn(CONFIGMAP_DEFAULT_LIST); - when(coreV1Api.listNamespacedSecret(eq("default"), eq(null), eq(null), eq(null), eq(null), eq(null), - eq(null), eq(null), eq(null), eq(null), eq(null), eq(null))) + when(coreV1Api.listNamespacedSecret( + "default", null, null, null, null, null, null, null, null, null, null, null)) .thenReturn(SECRET_DEFAULT_LIST); Environment mockNativeEnvironment = new Environment("gateway", "default"); @@ -340,9 +312,14 @@ public class CompositeKubernetesIntegrationTests { ResponseEntity response = new RestTemplate().exchange( "http://localhost:" + this.port + "/gateway/default", HttpMethod.GET, null, Environment.class); + Mockito.verify(coreV1Api, Mockito.times(1)).listNamespacedConfigMap( + "default", null, null, null, null, null, null, null, null, null, null, null); + + Mockito.verify(coreV1Api, Mockito.times(1)).listNamespacedSecret( + "default", null, null, null, null, null, null, null, null, null, null, null); + Environment environment = response.getBody(); - assert environment != null; assertThat(3).isEqualTo(environment.getPropertySources().size()); assertThat("nativeProperties").isEqualTo(environment.getPropertySources().get(0).getName()); assertThat(environment.getPropertySources().get(1).getName().contains("configmap.gateway.default.default") diff --git a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/it/ConfigDataConfigServerIntegrationTests.java b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/it/ConfigDataConfigServerIntegrationTests.java index 5f6e8120..90a3f295 100644 --- a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/it/ConfigDataConfigServerIntegrationTests.java +++ b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/it/ConfigDataConfigServerIntegrationTests.java @@ -17,6 +17,7 @@ package org.springframework.cloud.kubernetes.configserver.it; import com.github.tomakehurst.wiremock.client.WireMock; +import io.kubernetes.client.openapi.ApiClient; import io.kubernetes.client.util.ClientBuilder; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -43,17 +44,13 @@ class ConfigDataConfigServerIntegrationTests extends ConfigServerIntegration { @BeforeEach void setup() { clientUtilsMock = mockStatic(KubernetesClientUtils.class); - clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient) - .thenReturn(new ClientBuilder().setBasePath(wireMockServer.baseUrl()).build()); + ApiClient client = new ClientBuilder().setBasePath(wireMockServer.baseUrl()).build(); + clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient).thenReturn(client); } @AfterEach void teardown() { clientUtilsMock.close(); - } - - @AfterEach - void afterEach() { WireMock.reset(); } diff --git a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/it/ConfigServerIntegration.java b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/it/ConfigServerIntegration.java index 1924fd68..c7612834 100644 --- a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/it/ConfigServerIntegration.java +++ b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/it/ConfigServerIntegration.java @@ -26,6 +26,7 @@ import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; import io.kubernetes.client.openapi.models.V1SecretBuilder; import io.kubernetes.client.openapi.models.V1SecretList; import io.kubernetes.client.openapi.models.V1SecretListBuilder; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -46,6 +47,10 @@ import static org.assertj.core.api.Assertions.assertThat; */ abstract class ConfigServerIntegration { + private static final String SOURCE_NAME = "test-cm"; + + private static final String NAMESPACE = "default"; + private static final String TEST_CONFIG_MAP_DEV_YAML = "test-cm-dev.yaml"; private static final String TEST_CONFIG_MAP_DEV_NAME = "configmap.test-cm.default.dev"; private static final String TEST_CONFIG_MAP_DEV_DATA = """ @@ -85,6 +90,8 @@ abstract class ConfigServerIntegration { enabled: true """; + private static final String TEST_SECRET_NAME = "secret.test-cm.default.default"; + @Autowired private TestRestTemplate testRestTemplate; @@ -94,7 +101,7 @@ abstract class ConfigServerIntegration { @BeforeEach void beforeEach() { V1ConfigMapList TEST_CONFIGMAP = new V1ConfigMapList().addItemsItem(new V1ConfigMapBuilder().withMetadata( - new V1ObjectMetaBuilder().withName("test-cm").withNamespace("default").build()) + new V1ObjectMetaBuilder().withName(SOURCE_NAME).withNamespace(NAMESPACE).build()) .addToData(TEST_CONFIG_MAP_DEV_YAML, TEST_CONFIG_MAP_DEV_DATA) .addToData(TEST_CONFIG_MAP_QA_YAML, TEST_CONFIG_MAP_QA_DATA) .addToData(TEST_CONFIG_MAP_PROD_YAML, TEST_CONFIG_MAP_PROD_DATA) @@ -105,9 +112,8 @@ abstract class ConfigServerIntegration { V1SecretList TEST_SECRET = new V1SecretListBuilder() .withMetadata(new V1ListMetaBuilder().build()) .addToItems(new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("test-cm") - .withResourceVersion("0") - .withNamespace("default") + .withMetadata(new V1ObjectMetaBuilder().withName(SOURCE_NAME) + .withNamespace(NAMESPACE) .build()) .addToData("password", "p455w0rd".getBytes()) .addToData("username", "user".getBytes()) @@ -121,28 +127,25 @@ abstract class ConfigServerIntegration { .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(TEST_SECRET)))); } + @AfterEach + void afterEach() { + WireMock.reset(); + WireMock.shutdownServer(); + } + @Test void enabled() { - Environment env = testRestTemplate.getForObject("/test-cm/default", Environment.class); - assertThat(env.getPropertySources().size()).isEqualTo(2); - assertThat(env.getPropertySources().get(0).getName().equals("configmap.test-cm.default.default")).isTrue(); - assertThat(env.getPropertySources().get(0).getSource().get("app.name")).isEqualTo("test"); - assertThat(env.getPropertySources().get(1).getName().equals("secret.test-cm.default.default")).isTrue(); - assertThat(env.getPropertySources().get(1).getSource().get("password")).isEqualTo("p455w0rd"); - assertThat(env.getPropertySources().get(1).getSource().get("username")).isEqualTo("user"); + Environment defaultEnv = testRestTemplate.getForObject("/test-cm/default", Environment.class); + assertDefaultProfile(defaultEnv); - Environment devprod = testRestTemplate.getForObject("/test-cm/dev,prod", Environment.class); - assertThat(devprod.getPropertySources().size()).isEqualTo(4); + Environment devAndProd = testRestTemplate.getForObject("/test-cm/dev,prod", Environment.class); + assertThat(devAndProd.getPropertySources().size()).isEqualTo(4); - assertTestConfigMapProd(devprod); - assertTestConfigMapDev(devprod); - assertTestConfigMapDefault(devprod); + assertTestConfigMapProd(devAndProd); + assertTestConfigMapDev(devAndProd); + assertTestConfigMapDefault(devAndProd); + assertTestSecretDefault(devAndProd); - - assertThat(devprod.getPropertySources().get(3).getName().equals("secret.test-cm.default.default")).isTrue(); - assertThat(devprod.getPropertySources().get(3).getSource().size()).isEqualTo(2); - assertThat(devprod.getPropertySources().get(3).getSource().get("password")).isEqualTo("p455w0rd"); - assertThat(devprod.getPropertySources().get(3).getSource().get("username")).isEqualTo("user"); } private void assertTestConfigMapDev(Environment devAndProd) { @@ -156,23 +159,53 @@ abstract class ConfigServerIntegration { } private void assertTestConfigMapProd(Environment devAndProd) { - PropertySource testConfigMapDev = devAndProd.getPropertySources().get(0); - assertThat(testConfigMapDev.getName()).isEqualTo(TEST_CONFIG_MAP_PROD_NAME); + PropertySource testConfigMapProd = devAndProd.getPropertySources().get(0); + assertThat(testConfigMapProd.getName()).isEqualTo(TEST_CONFIG_MAP_PROD_NAME); @SuppressWarnings("unchecked") - Map data = (Map) testConfigMapDev.getSource(); + Map data = (Map) testConfigMapProd.getSource(); assertThat(data).containsExactlyInAnyOrderEntriesOf( Map.of("dummy.property.value", 3, "dummy.property.enabled", true, "dummy.property.profile", "prod")); } private void assertTestConfigMapDefault(Environment devAndProd) { - PropertySource testConfigMapDev = devAndProd.getPropertySources().get(2); - assertThat(testConfigMapDev.getName()).isEqualTo(TEST_CONFIG_MAP_NAME); + PropertySource testConfigMap = devAndProd.getPropertySources().get(2); + assertThat(testConfigMap.getName()).isEqualTo(TEST_CONFIG_MAP_NAME); @SuppressWarnings("unchecked") - Map data = (Map) testConfigMapDev.getSource(); + Map data = (Map) testConfigMap.getSource(); assertThat(data).containsExactlyInAnyOrderEntriesOf( - Map.of("dummy.property.value", 4, "dummy.property.enabled", true, "dummy.property.profile", "default")); + Map.of("dummy.property.value", 4, "dummy.property.enabled", true, "dummy.property.profile", "default", + "app.name", "test")); + } + + private void assertTestSecretDefault(Environment devAndProd) { + + PropertySource testSecret = devAndProd.getPropertySources().get(3); + assertThat(testSecret.getName()).isEqualTo(TEST_SECRET_NAME); + + @SuppressWarnings("unchecked") + Map data = (Map) testSecret.getSource(); + assertThat(data).containsExactlyInAnyOrderEntriesOf( + Map.of("password", "p455w0rd", "username", "user")); + } + + private void assertDefaultProfile(Environment defaultEnv) { + assertThat(defaultEnv.getPropertySources().size()).isEqualTo(2); + + PropertySource configMapSource = defaultEnv.getPropertySources().get(0); + assertThat(configMapSource.getName()).isEqualTo(TEST_CONFIG_MAP_NAME); + @SuppressWarnings("unchecked") + Map configmapData = (Map) configMapSource.getSource(); + assertThat(configmapData).containsExactlyInAnyOrderEntriesOf( + Map.of("dummy.property.value", 4, "dummy.property.enabled", true, "dummy.property.profile", "default", + "app.name", "test")); + + PropertySource secretSource = defaultEnv.getPropertySources().get(1); + assertThat(secretSource.getName()).isEqualTo(TEST_SECRET_NAME); + @SuppressWarnings("unchecked") + Map secretData = (Map) secretSource.getSource(); + assertThat(secretData).containsExactlyInAnyOrderEntriesOf(Map.of("password", "p455w0rd", "username", "user")); } }