diff --git a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/ConfigServerAutoConfigurationKubernetesDisabledTests.java b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/ConfigServerAutoConfigurationKubernetesDisabledTests.java index 1864cdbd2d..ee0385300c 100644 --- a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/ConfigServerAutoConfigurationKubernetesDisabledTests.java +++ b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/ConfigServerAutoConfigurationKubernetesDisabledTests.java @@ -20,6 +20,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.kubernetes.configserver.configurations.MockConfig; import org.springframework.context.ConfigurableApplicationContext; import static org.assertj.core.api.Assertions.assertThat; @@ -28,7 +29,7 @@ * @author Ryan Baxter */ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - properties = { "spring.profiles.include=kubernetes,kubernetesdisabled" }, + properties = { "spring.profiles.include=kubernetes,kubernetesdisabled", "test.first.config.enabled=true" }, classes = { KubernetesConfigServerApplication.class, MockConfig.class }) class ConfigServerAutoConfigurationKubernetesDisabledTests { diff --git a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/ConfigServerAutoConfigurationKubernetesProfileMissingTests.java b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/ConfigServerAutoConfigurationKubernetesProfileMissingTests.java index 2d507599da..78d4fefe69 100644 --- a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/ConfigServerAutoConfigurationKubernetesProfileMissingTests.java +++ b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/ConfigServerAutoConfigurationKubernetesProfileMissingTests.java @@ -20,6 +20,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.kubernetes.configserver.configurations.MockConfig; import org.springframework.context.ConfigurableApplicationContext; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/KubernetesEnvironmentRepositoryFactoryTests.java b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/KubernetesEnvironmentRepositoryFactoryTests.java index e99b83ad88..5df4686912 100644 --- a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/KubernetesEnvironmentRepositoryFactoryTests.java +++ b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/KubernetesEnvironmentRepositoryFactoryTests.java @@ -18,21 +18,17 @@ import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.cloud.config.server.environment.EnvironmentRepository; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; +import org.springframework.cloud.kubernetes.configserver.configurations.ThirdConfig; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -@SpringJUnitConfig -@SpringBootTest +@SpringBootTest(classes = ThirdConfig.class, properties = "test.third.config.enabled=true") class KubernetesEnvironmentRepositoryFactoryTests { - @MockBean + @Autowired private KubernetesEnvironmentRepository mockRepository; @Test @@ -47,20 +43,4 @@ void testBuild() { assertThat(repository).isSameAs(mockRepository); } - @Configuration - static class TestConfig { - - @Bean - public KubernetesEnvironmentRepository kubernetesEnvironmentRepository() { - return mock(KubernetesEnvironmentRepository.class); - } - - @Bean - public KubernetesEnvironmentRepositoryFactory kubernetesEnvironmentRepositoryFactory( - KubernetesEnvironmentRepository kubernetesEnvironmentRepository) { - return new KubernetesEnvironmentRepositoryFactory(kubernetesEnvironmentRepository); - } - - } - } diff --git a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/KubernetesEnvironmentRepositoryTests.java b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/KubernetesEnvironmentRepositoryTests.java index 0901176e4c..6fb2ec39b9 100644 --- a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/KubernetesEnvironmentRepositoryTests.java +++ b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/KubernetesEnvironmentRepositoryTests.java @@ -36,6 +36,7 @@ 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.client.config.KubernetesClientSecretsCache; import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsPropertySource; import org.springframework.cloud.kubernetes.commons.config.ConfigUtils; import org.springframework.cloud.kubernetes.commons.config.Constants; @@ -89,39 +90,33 @@ class KubernetesEnvironmentRepositoryTests { private static final V1ConfigMapList CONFIGMAP_DEV_LIST = new V1ConfigMapList() .addItemsItem(new V1ConfigMapBuilder() - .withMetadata( - new V1ObjectMetaBuilder().withName("stores").withNamespace("dev").withResourceVersion("1").build()) + .withMetadata(new V1ObjectMetaBuilder().withName("stores").withNamespace("dev").build()) .addToData(Constants.APPLICATION_YAML, "dummy:\n property:\n string2: \"dev\"\n int2: 1\n bool2: true\n") .build()); private static final V1SecretList SECRET_LIST = new V1SecretListBuilder() - .addToItems( - new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("application") - .withResourceVersion("0") - .withNamespace("default") - .build()) - .addToData("password", "p455w0rd".getBytes()) - .addToData("username", "user".getBytes()) - .build()) - .addToItems(new V1SecretBuilder().withMetadata( - new V1ObjectMetaBuilder().withName("stores").withResourceVersion("0").withNamespace("default").build()) + .addToItems(new V1SecretBuilder() + .withMetadata(new V1ObjectMetaBuilder().withName("application").withNamespace("default").build()) + .addToData("password", "p455w0rd".getBytes()) + .addToData("username", "user".getBytes()) + .build()) + .addToItems(new V1SecretBuilder() + .withMetadata(new V1ObjectMetaBuilder().withName("stores").withNamespace("default").build()) .addToData("password", "password-from-stores".getBytes()) .addToData("username", "stores".getBytes()) .build()) .addToItems(new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("stores-dev") - .withResourceVersion("0") - .withNamespace("default") - .build()) + .withMetadata(new V1ObjectMetaBuilder().withName("stores-dev").withNamespace("default").build()) .addToData("password", "password-from-stores-dev".getBytes()) .addToData("username", "stores-dev".getBytes()) .build()) .build(); + private static final KubernetesConfigServerProperties PROPERTIES = properties(); + @BeforeAll - public static void before() { + static void before() { KUBERNETES_PROPERTY_SOURCE_SUPPLIER.add((coreApi, applicationName, namespace, springEnv) -> { List propertySources = new ArrayList<>(); @@ -152,8 +147,9 @@ public static void before() { } @AfterEach - public void after() { + void after() { new KubernetesClientConfigMapsCache().discardAll(); + new KubernetesClientSecretsCache().discardAll(); } @Test @@ -169,7 +165,7 @@ public void testApplicationCase() throws ApiException { eq(null), eq(null), eq(null), eq(null), eq(null))) .thenReturn(CONFIGMAP_DEV_LIST); KubernetesEnvironmentRepository environmentRepository = new KubernetesEnvironmentRepository(coreApi, - KUBERNETES_PROPERTY_SOURCE_SUPPLIER, "default"); + KUBERNETES_PROPERTY_SOURCE_SUPPLIER, "default", PROPERTIES); Environment environment = environmentRepository.findOne("application", "", ""); assertThat(environment.getPropertySources().size()).isEqualTo(2); environment.getPropertySources().forEach(propertySource -> { @@ -245,7 +241,7 @@ public void testStoresCase() throws ApiException { eq(null), eq(null), eq(null), eq(null), eq(null))) .thenReturn(SECRET_LIST); KubernetesEnvironmentRepository environmentRepository = new KubernetesEnvironmentRepository(coreApi, - KUBERNETES_PROPERTY_SOURCE_SUPPLIER, "default"); + KUBERNETES_PROPERTY_SOURCE_SUPPLIER, "default", PROPERTIES); Environment environment = environmentRepository.findOne("stores", "", ""); assertThat(environment.getPropertySources().size()).isEqualTo(4); environment.getPropertySources().forEach(propertySource -> { @@ -292,7 +288,7 @@ public void testStoresProfileCase() throws ApiException { eq(null), eq(null), eq(null), eq(null), eq(null))) .thenReturn(CONFIGMAP_DEV_LIST); KubernetesEnvironmentRepository environmentRepository = new KubernetesEnvironmentRepository(coreApi, - KUBERNETES_PROPERTY_SOURCE_SUPPLIER, "default"); + KUBERNETES_PROPERTY_SOURCE_SUPPLIER, "default", PROPERTIES); Environment environment = environmentRepository.findOne("stores", "dev", ""); assertThat(environment.getPropertySources().size()).isEqualTo(6); environment.getPropertySources().forEach(propertySource -> { @@ -356,7 +352,7 @@ public void testApplicationPropertiesAnSecretsOverride() throws ApiException { eq(null), eq(null), eq(null), eq(null), eq(null))) .thenReturn(CONFIGMAP_DEV_LIST); KubernetesEnvironmentRepository environmentRepository = new KubernetesEnvironmentRepository(coreApi, - KUBERNETES_PROPERTY_SOURCE_SUPPLIER, "default"); + KUBERNETES_PROPERTY_SOURCE_SUPPLIER, "default", PROPERTIES); Environment environment = environmentRepository.findOne("stores-dev", "", ""); environment.getPropertySources() .stream() @@ -404,7 +400,7 @@ public void testSingleConfigMapMultipleSources() throws ApiException { return propertySources; }); KubernetesEnvironmentRepository environmentRepository = new KubernetesEnvironmentRepository(coreApi, suppliers, - "default"); + "default", PROPERTIES); Environment environment = environmentRepository.findOne("storessingle", "", ""); assertThat(environment.getPropertySources().size()).isEqualTo(1); assertThat(environment.getPropertySources().get(0).getName()) @@ -434,4 +430,10 @@ public void testSingleConfigMapMultipleSources() throws ApiException { } + private static KubernetesConfigServerProperties properties() { + KubernetesConfigServerProperties properties = new KubernetesConfigServerProperties(); + properties.setOrder(1); + return properties; + } + } diff --git a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/KubernetesPropertySourceSupplierTests.java b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/KubernetesPropertySourceSupplierTests.java index 3b2e7a5e03..a6aaba092c 100644 --- a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/KubernetesPropertySourceSupplierTests.java +++ b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/KubernetesPropertySourceSupplierTests.java @@ -27,15 +27,18 @@ import io.kubernetes.client.openapi.models.V1Secret; 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.AfterAll; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.mockito.Mockito; import org.springframework.cloud.config.environment.Environment; +import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapsCache; +import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsCache; import org.springframework.cloud.kubernetes.commons.config.Constants; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -47,7 +50,7 @@ */ class KubernetesPropertySourceSupplierTests { - private static final CoreV1Api coreApi = mock(CoreV1Api.class); + private static final CoreV1Api CORE_V1_API = mock(CoreV1Api.class); private static final V1ConfigMapList CONFIGMAP_DEFAULT_LIST = new V1ConfigMapList() .addItemsItem(buildConfigMap("gateway", "default")); @@ -58,41 +61,51 @@ class KubernetesPropertySourceSupplierTests { private static final V1ConfigMapList CONFIGMAP_TEAM_B_LIST = new V1ConfigMapList() .addItemsItem(buildConfigMap("orders", "team-b")); - private static final V1SecretList SECRET_DEFAULT_LIST = new V1SecretListBuilder() - .addToItems(buildSecret("gateway", "default")) - .build(); + private static final V1SecretList SECRET_DEFAULT_LIST = new V1SecretList() + .addItemsItem(buildSecret("gateway", "default")); - private static final V1SecretList SECRET_TEAM_A_LIST = new V1SecretListBuilder() - .addToItems(buildSecret("stores", "team-a")) - .build(); + private static final V1SecretList SECRET_TEAM_A_LIST = new V1SecretList() + .addItemsItem(buildSecret("stores", "team-a")); - private static final V1SecretList SECRET_TEAM_B_LIST = new V1SecretListBuilder() - .addToItems(buildSecret("orders", "team-b")) - .build(); + private static final V1SecretList SECRET_TEAM_B_LIST = new V1SecretList() + .addItemsItem(buildSecret("orders", "team-b")); + + private static final KubernetesConfigServerProperties PROPERTIES = properties(); @BeforeAll - public static void before() throws ApiException { - when(coreApi.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))) + static void beforeAll() throws ApiException { + when(CORE_V1_API.listNamespacedConfigMap("default", null, null, null, null, null, null, null, null, null, null, + null)) .thenReturn(CONFIGMAP_DEFAULT_LIST); - when(coreApi.listNamespacedConfigMap(eq("team-a"), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), - eq(null), eq(null), eq(null), eq(null), eq(null))) + when(CORE_V1_API.listNamespacedConfigMap("team-a", null, null, null, null, null, null, null, null, null, null, + null)) .thenReturn(CONFIGMAP_TEAM_A_LIST); - when(coreApi.listNamespacedConfigMap(eq("team-b"), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), - eq(null), eq(null), eq(null), eq(null), eq(null))) + when(CORE_V1_API.listNamespacedConfigMap("team-b", null, null, null, null, null, null, null, null, null, null, + null)) .thenReturn(CONFIGMAP_TEAM_B_LIST); - when(coreApi.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(CORE_V1_API.listNamespacedSecret("default", null, null, null, null, null, null, null, null, null, null, + null)) .thenReturn(SECRET_DEFAULT_LIST); - when(coreApi.listNamespacedSecret(eq("team-a"), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), - eq(null), eq(null), eq(null), eq(null), eq(null))) + when(CORE_V1_API.listNamespacedSecret("team-a", null, null, null, null, null, null, null, null, null, null, + null)) .thenReturn(SECRET_TEAM_A_LIST); - when(coreApi.listNamespacedSecret(eq("team-b"), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), - eq(null), eq(null), eq(null), eq(null), eq(null))) + when(CORE_V1_API.listNamespacedSecret("team-b", null, null, null, null, null, null, null, null, null, null, + null)) .thenReturn(SECRET_TEAM_B_LIST); } + @AfterAll + static void afterAll() { + Mockito.reset(CORE_V1_API); + } + + @AfterEach + void afterEach() { + new KubernetesClientConfigMapsCache().discardAll(); + new KubernetesClientSecretsCache().discardAll(); + } + @Test void whenCurrentAndExtraNamespacesAddedThenAllConfigMapsAreIncluded() { KubernetesConfigServerProperties kubernetesConfigServerProperties = new KubernetesConfigServerProperties(); @@ -101,8 +114,8 @@ void whenCurrentAndExtraNamespacesAddedThenAllConfigMapsAreIncluded() { KubernetesPropertySourceSupplier kubernetesPropertySourceSupplier = new KubernetesConfigServerAutoConfiguration() .configMapPropertySourceSupplier(kubernetesConfigServerProperties); - KubernetesEnvironmentRepository environmentRepository = new KubernetesEnvironmentRepository(coreApi, - Collections.singletonList(kubernetesPropertySourceSupplier), "default"); + KubernetesEnvironmentRepository environmentRepository = new KubernetesEnvironmentRepository(CORE_V1_API, + Collections.singletonList(kubernetesPropertySourceSupplier), "default", PROPERTIES); Environment environmentGateway = environmentRepository.findOne("gateway", "", ""); assertThat(environmentGateway.getPropertySources().size()).isEqualTo(1); @@ -122,8 +135,8 @@ void whenExtraNamespacesAddedThenConfigMapsInCurrentNamespaceAreNotIncluded() { KubernetesPropertySourceSupplier kubernetesPropertySourceSupplier = new KubernetesConfigServerAutoConfiguration() .configMapPropertySourceSupplier(kubernetesConfigServerProperties); - KubernetesEnvironmentRepository environmentRepository = new KubernetesEnvironmentRepository(coreApi, - Collections.singletonList(kubernetesPropertySourceSupplier), "default"); + KubernetesEnvironmentRepository environmentRepository = new KubernetesEnvironmentRepository(CORE_V1_API, + Collections.singletonList(kubernetesPropertySourceSupplier), "default", PROPERTIES); Environment environmentGateway = environmentRepository.findOne("gateway", "", ""); assertThat(environmentGateway.getPropertySources().size()).isEqualTo(0); @@ -143,8 +156,8 @@ void whenCurrentAndExtraNamespacesAddedThenAllSecretsAreIncluded() { KubernetesPropertySourceSupplier kubernetesPropertySourceSupplier = new KubernetesConfigServerAutoConfiguration() .secretsPropertySourceSupplier(kubernetesConfigServerProperties); - KubernetesEnvironmentRepository environmentRepository = new KubernetesEnvironmentRepository(coreApi, - Collections.singletonList(kubernetesPropertySourceSupplier), "default"); + KubernetesEnvironmentRepository environmentRepository = new KubernetesEnvironmentRepository(CORE_V1_API, + Collections.singletonList(kubernetesPropertySourceSupplier), "default", PROPERTIES); Environment environmentGateway = environmentRepository.findOne("gateway", "", ""); assertThat(environmentGateway.getPropertySources().size()).isEqualTo(1); @@ -164,8 +177,8 @@ void whenExtraNamespacesAddedThenSecretsInCurrentNamespaceAreNotIncluded() { KubernetesPropertySourceSupplier kubernetesPropertySourceSupplier = new KubernetesConfigServerAutoConfiguration() .secretsPropertySourceSupplier(kubernetesConfigServerProperties); - KubernetesEnvironmentRepository environmentRepository = new KubernetesEnvironmentRepository(coreApi, - Collections.singletonList(kubernetesPropertySourceSupplier), "default"); + KubernetesEnvironmentRepository environmentRepository = new KubernetesEnvironmentRepository(CORE_V1_API, + Collections.singletonList(kubernetesPropertySourceSupplier), "default", PROPERTIES); Environment environmentGateway = environmentRepository.findOne("gateway", "", ""); assertThat(environmentGateway.getPropertySources().size()).isEqualTo(0); @@ -179,19 +192,25 @@ void whenExtraNamespacesAddedThenSecretsInCurrentNamespaceAreNotIncluded() { private static V1ConfigMap buildConfigMap(String name, String namespace) { return new V1ConfigMapBuilder() - .withMetadata( - new V1ObjectMetaBuilder().withName(name).withNamespace(namespace).withResourceVersion("1").build()) - .addToData(Constants.APPLICATION_YAML, "dummy:\n property:\n string: \"" + name + "\"\n") + .withMetadata(new V1ObjectMetaBuilder().withName(name).withNamespace(namespace).build()) + .addToData(Constants.APPLICATION_PROPERTIES, """ + dummy.property.string=%s + """.formatted(name)) .build(); } private static V1Secret buildSecret(String name, String namespace) { return new V1SecretBuilder() - .withMetadata( - new V1ObjectMetaBuilder().withName(name).withResourceVersion("0").withNamespace(namespace).build()) + .withMetadata(new V1ObjectMetaBuilder().withName(name).withNamespace(namespace).build()) .addToData("password", "p455w0rd".getBytes()) .addToData("username", "user".getBytes()) .build(); } + private static KubernetesConfigServerProperties properties() { + KubernetesConfigServerProperties properties = new KubernetesConfigServerProperties(); + properties.setOrder(1); + return properties; + } + } diff --git a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/TestBootstrapConfig.java b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/configurations/FirstConfig.java similarity index 76% rename from spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/TestBootstrapConfig.java rename to spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/configurations/FirstConfig.java index b93a81ed50..2c3a3348ea 100644 --- a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/TestBootstrapConfig.java +++ b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/configurations/FirstConfig.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cloud.kubernetes.configserver; +package org.springframework.cloud.kubernetes.configserver.configurations; import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.client.WireMock; @@ -22,14 +22,18 @@ import io.kubernetes.client.openapi.apis.CoreV1Api; import io.kubernetes.client.util.ClientBuilder; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; /** * @author Ryan Baxter */ -public class TestBootstrapConfig { +@Configuration +@ConditionalOnProperty(value = "test.first.config.enabled", havingValue = "true", matchIfMissing = false) +public class FirstConfig { @Bean WireMockServer wireMockServer() { @@ -41,9 +45,7 @@ WireMockServer wireMockServer() { @Bean ApiClient apiClient(WireMockServer wireMockServer) { - ApiClient apiClient = new ClientBuilder().setBasePath(wireMockServer.baseUrl()).build(); - apiClient.setDebugging(true); - return apiClient; + return new ClientBuilder().setBasePath(wireMockServer.baseUrl()).build(); } @Bean diff --git a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/MockConfig.java b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/configurations/MockConfig.java similarity index 91% rename from spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/MockConfig.java rename to spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/configurations/MockConfig.java index 0fdc064537..379640e23d 100644 --- a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/MockConfig.java +++ b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/configurations/MockConfig.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cloud.kubernetes.configserver; +package org.springframework.cloud.kubernetes.configserver.configurations; import org.springframework.cloud.config.server.environment.EnvironmentRepository; import org.springframework.context.annotation.Bean; @@ -24,7 +24,7 @@ import static org.mockito.Mockito.mock; @Configuration -class MockConfig { +public class MockConfig { @Bean @Profile("kubernetesdisabled") diff --git a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/configurations/SecondConfig.java b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/configurations/SecondConfig.java new file mode 100644 index 0000000000..e3c97ad767 --- /dev/null +++ b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/configurations/SecondConfig.java @@ -0,0 +1,94 @@ +/* + * Copyright 2013-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.kubernetes.configserver.configurations; + +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.client.WireMock; +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.openapi.JSON; +import io.kubernetes.client.openapi.apis.CoreV1Api; +import io.kubernetes.client.openapi.models.V1ConfigMap; +import io.kubernetes.client.openapi.models.V1ConfigMapBuilder; +import io.kubernetes.client.openapi.models.V1ConfigMapList; +import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; +import io.kubernetes.client.openapi.models.V1Secret; +import io.kubernetes.client.openapi.models.V1SecretBuilder; +import io.kubernetes.client.openapi.models.V1SecretList; +import io.kubernetes.client.util.ClientBuilder; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.kubernetes.commons.config.Constants; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; + +/** + * @author wind57 + */ +@Configuration +@ConditionalOnProperty(value = "test.second.config.enabled", havingValue = "true", matchIfMissing = false) +public class SecondConfig { + + private static V1ConfigMap buildConfigMap() { + return new V1ConfigMapBuilder() + .withMetadata(new V1ObjectMetaBuilder().withName("gateway").withNamespace("default").build()) + .addToData(Constants.APPLICATION_PROPERTIES, "dummy.property.string=gateway") + .build(); + } + + private static V1Secret buildSecret() { + return new V1SecretBuilder() + .withMetadata(new V1ObjectMetaBuilder().withName("gateway").withNamespace("default").build()) + .addToData("password", "p455w0rd".getBytes()) + .addToData("username", "user".getBytes()) + .build(); + } + + private static final V1ConfigMapList CONFIGMAP_DEFAULT_LIST = new V1ConfigMapList().addItemsItem(buildConfigMap()); + + private static final V1SecretList SECRET_DEFAULT_LIST = new V1SecretList().addItemsItem(buildSecret()); + + @Bean + WireMockServer wireMockServer() { + WireMockServer wireMockServer = new WireMockServer(options().dynamicPort()); + wireMockServer.start(); + WireMock.configureFor(wireMockServer.port()); + + WireMock.stubFor(get(urlMatching("^/api/v1/namespaces/default/configmaps.*")) + .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(CONFIGMAP_DEFAULT_LIST)))); + + WireMock.stubFor(get(urlMatching("^/api/v1/namespaces/default/secrets.*")) + .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(SECRET_DEFAULT_LIST)))); + + return wireMockServer; + } + + @Bean + ApiClient apiClient(WireMockServer wireMockServer) { + return new ClientBuilder().setBasePath(wireMockServer.baseUrl()).build(); + } + + @Bean + CoreV1Api coreApi(ApiClient apiClient) { + return new CoreV1Api(apiClient); + } + +} diff --git a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/configurations/ThirdConfig.java b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/configurations/ThirdConfig.java new file mode 100644 index 0000000000..a422aaadef --- /dev/null +++ b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/configurations/ThirdConfig.java @@ -0,0 +1,42 @@ +/* + * Copyright 2013-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.kubernetes.configserver.configurations; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.kubernetes.configserver.KubernetesEnvironmentRepository; +import org.springframework.cloud.kubernetes.configserver.KubernetesEnvironmentRepositoryFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.mockito.Mockito.mock; + +@Configuration +@ConditionalOnProperty(value = "test.third.config.enabled", havingValue = "true", matchIfMissing = false) +public class ThirdConfig { + + @Bean + public KubernetesEnvironmentRepository kubernetesEnvironmentRepository() { + return mock(KubernetesEnvironmentRepository.class); + } + + @Bean + public KubernetesEnvironmentRepositoryFactory kubernetesEnvironmentRepositoryFactory( + KubernetesEnvironmentRepository kubernetesEnvironmentRepository) { + return new KubernetesEnvironmentRepositoryFactory(kubernetesEnvironmentRepository); + } + +} diff --git a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/it/BootstrapConfigServerIntegrationTests.java b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/it/BootstrapConfigServerIntegrationTests.java index 67a2250ff7..951061a69b 100644 --- a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/it/BootstrapConfigServerIntegrationTests.java +++ b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/java/org/springframework/cloud/kubernetes/configserver/it/BootstrapConfigServerIntegrationTests.java @@ -25,7 +25,7 @@ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { "spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.client.namespace=default", "spring.profiles.include=kubernetes", "spring.cloud.kubernetes.secrets.enableApi=true", - "spring.cloud.bootstrap.enabled=true" }, + "spring.cloud.bootstrap.enabled=true", "test.first.config.enabled=true" }, classes = { KubernetesConfigServerApplication.class }) class BootstrapConfigServerIntegrationTests extends ConfigServerIntegration { 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 00c0789330..fd1d270b51 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,41 +16,20 @@ 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; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.openapi.models.V1ConfigMap; -import io.kubernetes.client.openapi.models.V1ConfigMapBuilder; -import io.kubernetes.client.openapi.models.V1ConfigMapList; -import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder; -import io.kubernetes.client.openapi.models.V1Secret; -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.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.SpyBean; 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,59 +44,18 @@ /** * @author Arjav Dongaonkar */ -public class CompositeKubernetesIntegrationTests { - - private static final List KUBERNETES_PROPERTY_SOURCE_SUPPLIER = new ArrayList<>(); - - private static V1ConfigMap buildConfigMap(String name, String namespace) { - return new V1ConfigMapBuilder() - .withMetadata( - new V1ObjectMetaBuilder().withName(name).withNamespace(namespace).withResourceVersion("1").build()) - .addToData(Constants.APPLICATION_YAML, "dummy:\n property:\n string: \"" + name + "\"\n") - .build(); - } - - private static V1Secret buildSecret(String name, String namespace) { - return new V1SecretBuilder() - .withMetadata( - new V1ObjectMetaBuilder().withName(name).withResourceVersion("0").withNamespace(namespace).build()) - .addToData("password", "p455w0rd".getBytes()) - .addToData("username", "user".getBytes()) - .build(); - } - - private static final V1ConfigMapList CONFIGMAP_DEFAULT_LIST = new V1ConfigMapList() - .addItemsItem(buildConfigMap("gateway", "default")); - - private static final V1SecretList SECRET_DEFAULT_LIST = new V1SecretListBuilder() - .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; - }); - } +class CompositeKubernetesIntegrationTests { @AfterEach - public void after() { + void after() { new KubernetesClientConfigMapsCache().discardAll(); } @Nested @SpringBootTest(classes = { KubernetesConfigServerApplication.class }, properties = { "spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.client.namespace=default", - "spring.config.name=compositeconfigserver", "spring.cloud.config.server.composite[0].type=kubernetes", - "spring.cloud.kubernetes.secrets.enableApi=true" }, + "spring.cloud.kubernetes.secrets.enableApi=true", "test.second.config.enabled=true" }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @ActiveProfiles({ "test", "composite", "kubernetes" }) class KubernetesCompositeConfigServerTest { @@ -125,27 +63,18 @@ class KubernetesCompositeConfigServerTest { @LocalServerPort private int port; - @MockBean - 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))) - .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))) - .thenReturn(SECRET_DEFAULT_LIST); + void contextLoads() { ResponseEntity response = new RestTemplate().exchange( "http://localhost:" + this.port + "/gateway/default", HttpMethod.GET, null, Environment.class); Environment environment = response.getBody(); assertThat(environment).isNotNull(); - assertThat(environment.getPropertySources()).hasSize(4); + assertThat(environment.getPropertySources().size()).isEqualTo(4); assertThat(environment.getPropertySources().get(0).getName()) .isEqualTo("configmap.gateway.default.default"); - assertThat(environment.getPropertySources().get(1).getName()).contains("secret.gateway.default.default"); + assertThat(environment.getPropertySources().get(1).getName()).isEqualTo("secret.gateway.default.default"); } } @@ -155,29 +84,19 @@ public void contextLoads() throws ApiException { 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" }, + "spring.cloud.kubernetes.secrets.enableApi=true", + "spring.profiles.active=test, composite, kubernetes, native", "test.second.config.enabled=true" }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) - @ActiveProfiles({ "test", "composite", "kubernetes", "native" }) class KubernetesSecretsEnabledCompositeConfigServerTest { @LocalServerPort private int port; - @MockBean - private CoreV1Api coreV1Api; - @SpyBean 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))) - .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))) - .thenReturn(SECRET_DEFAULT_LIST); + void contextLoads() { Environment mockNativeEnvironment = new Environment("gateway", "default"); mockNativeEnvironment.add(new PropertySource("nativeProperties", Map.of("key1", "value1"))); @@ -190,13 +109,12 @@ public void contextLoads() throws Exception { Environment environment = response.getBody(); assertThat(environment).isNotNull(); - assertThat(environment.getPropertySources()).hasSizeGreaterThanOrEqualTo(5); + assertThat(environment.getPropertySources().size()).isEqualTo(5); assertThat(environment.getPropertySources().get(0).getName()) .isEqualTo("configmap.gateway.default.default"); assertThat(environment.getPropertySources().get(1).getName()).contains("secret.gateway.default.default"); - assertThat(environment.getPropertySources()).anyMatch(ps -> ps.getName().contains("native")); } } @@ -206,30 +124,19 @@ public void contextLoads() throws Exception { 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" }, + "spring.cloud.kubernetes.config.enableApi=false", "spring.cloud.kubernetes.secrets.enableApi=true", + "spring.profiles.active=test ,composite, kubernetes, native", "test.second.config.enabled=true" }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) - @ActiveProfiles({ "test", "composite", "kubernetes", "native" }) class KubernetesConfigMapDisabledCompositeConfigServerTest { @LocalServerPort private int port; - @MockBean - private CoreV1Api coreV1Api; - @SpyBean 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))) - .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))) - .thenReturn(SECRET_DEFAULT_LIST); + void contextLoads() { Environment mockNativeEnvironment = new Environment("gateway", "default"); mockNativeEnvironment.add(new PropertySource("nativeProperties", Map.of("key1", "value1"))); @@ -242,12 +149,11 @@ public void contextLoads() throws Exception { Environment environment = response.getBody(); assertThat(environment).isNotNull(); - assertThat(environment.getPropertySources()).hasSizeGreaterThanOrEqualTo(3); + assertThat(environment.getPropertySources().size()).isEqualTo(3); assertThat(environment.getPropertySources().get(0).getName()).isEqualTo("secret.gateway.default.default"); - assertThat(environment.getPropertySources().get(1).getName()).contains("nativeProperties"); + assertThat(environment.getPropertySources().get(1).getName()).isEqualTo("nativeProperties"); - assertThat(environment.getPropertySources()).anyMatch(ps -> ps.getName().contains("native")); } } @@ -257,28 +163,18 @@ public void contextLoads() throws Exception { 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.profiles.active=test, composite, kubernetes, native", "test.second.config.enabled=true" }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) - @ActiveProfiles({ "test", "composite", "kubernetes", "native" }) class KubernetesSecretsDisabledCompositeConfigServerTest { @LocalServerPort private int port; - @MockBean - private CoreV1Api coreV1Api; - @SpyBean 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))) - .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))) - .thenReturn(SECRET_DEFAULT_LIST); + void contextLoads() { Environment mockNativeEnvironment = new Environment("gateway", "default"); mockNativeEnvironment.add(new PropertySource("nativeProperties", Map.of("key1", "value1"))); @@ -291,64 +187,51 @@ public void contextLoads() throws Exception { Environment environment = response.getBody(); assertThat(environment).isNotNull(); - assertThat(environment.getPropertySources()).hasSizeGreaterThanOrEqualTo(3); + assertThat(environment.getPropertySources().size()).isEqualTo(3); assertThat(environment.getPropertySources().get(0).getName()) .isEqualTo("configmap.gateway.default.default"); - assertThat(environment.getPropertySources().get(1).getName()).contains("nativeProperties"); + assertThat(environment.getPropertySources().get(1).getName()).isEqualTo("nativeProperties"); - assertThat(environment.getPropertySources()).anyMatch(ps -> ps.getName().contains("native")); } } @Nested @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", + properties = { "spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.client.namespace=default", "spring.cloud.config.server.native.order=1", "spring.cloud.kubernetes.configserver.order=2", - "spring.cloud.kubernetes.secrets.enableApi=true" }, + "spring.cloud.kubernetes.secrets.enableApi=true", "test.second.config.enabled=true", + "spring.profiles.active=test, native, kubernetes" }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) - @ActiveProfiles({ "test", "native", "kubernetes" }) class NativeAndKubernetesConfigServerTest { @LocalServerPort private int port; - @MockBean - private CoreV1Api coreV1Api; - @SpyBean 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))) - .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))) - .thenReturn(SECRET_DEFAULT_LIST); + void contextLoads() { - Environment mockNativeEnvironment = new Environment("gateway", "default"); - mockNativeEnvironment.add(new PropertySource("nativeProperties", Map.of("key1", "value1"))); + Environment nativeEnvironment = new Environment("gateway", "default"); + nativeEnvironment.add(new PropertySource("nativeProperties", Map.of("key1", "value1"))); when(nativeEnvironmentRepository.findOne(anyString(), anyString(), eq(null), anyBoolean())) - .thenReturn(mockNativeEnvironment); + .thenReturn(nativeEnvironment); ResponseEntity response = new RestTemplate().exchange( "http://localhost:" + this.port + "/gateway/default", HttpMethod.GET, null, Environment.class); 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") - && !environment.getPropertySources().get(1).getName().contains("nativeProperties")) - .isTrue(); - assertThat(environment.getPropertySources().get(2).getName()).contains("secret.gateway.default.default"); + assertThat(environment.getPropertySources().size()).isEqualTo(3); + assertThat(environment.getPropertySources().get(0).getName()).isEqualTo("nativeProperties"); + assertThat(environment.getPropertySources().get(1).getName()) + .isEqualTo("configmap.gateway.default.default"); + assertThat(environment.getPropertySources().get(2).getName()).isEqualTo("secret.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 5f6e81208b..1547dd463a 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 @@ -16,45 +16,18 @@ package org.springframework.cloud.kubernetes.configserver.it; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.util.ClientBuilder; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.mockito.MockedStatic; - import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.kubernetes.client.KubernetesClientUtils; import org.springframework.cloud.kubernetes.configserver.KubernetesConfigServerApplication; -import org.springframework.cloud.kubernetes.configserver.TestBootstrapConfig; - -import static org.mockito.Mockito.mockStatic; +import org.springframework.cloud.kubernetes.configserver.configurations.FirstConfig; /** * @author Ryan Baxter */ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { "spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.client.namespace=default", - "spring.profiles.include=kubernetes", "spring.cloud.kubernetes.secrets.enableApi=true" }, - classes = { KubernetesConfigServerApplication.class, TestBootstrapConfig.class }) + "spring.profiles.include=kubernetes", "spring.cloud.kubernetes.secrets.enableApi=true", + "test.first.config.enabled=true" }, + classes = { KubernetesConfigServerApplication.class, FirstConfig.class }) class ConfigDataConfigServerIntegrationTests extends ConfigServerIntegration { - private MockedStatic clientUtilsMock; - - @BeforeEach - void setup() { - clientUtilsMock = mockStatic(KubernetesClientUtils.class); - clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient) - .thenReturn(new ClientBuilder().setBasePath(wireMockServer.baseUrl()).build()); - } - - @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 0ec76fce23..eea41166af 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 @@ -16,6 +16,8 @@ package org.springframework.cloud.kubernetes.configserver.it; +import java.util.Map; + import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.client.WireMock; import io.kubernetes.client.openapi.JSON; @@ -26,12 +28,16 @@ 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; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.cloud.config.environment.Environment; +import org.springframework.cloud.config.environment.PropertySource; +import org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigMapsCache; +import org.springframework.cloud.kubernetes.client.config.KubernetesClientSecretsCache; import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import static com.github.tomakehurst.wiremock.client.WireMock.get; @@ -43,6 +49,50 @@ */ 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_PROPERTIES = "test-cm-dev.properties"; + + private static final String TEST_CONFIG_MAP_DEV_NAME = "configmap.test-cm.default.dev"; + + private static final String TEST_CONFIG_MAP_DEV_DATA = """ + dummy.property.profile=dev + dummy.property.value=1 + dummy.property.enabled=false + """; + + private static final String TEST_CONFIG_MAP_QA_PROPERTIES = "test-cm-qa.properties"; + + private static final String TEST_CONFIG_MAP_QA_DATA = """ + dummy.property.profile=qa + dummy.property.value=2 + dummy.property.enabled=true + """; + + private static final String TEST_CONFIG_MAP_PROD_PROPERTIES = "test-cm-prod.properties"; + + private static final String TEST_CONFIG_MAP_PROD_NAME = "configmap.test-cm.default.prod"; + + private static final String TEST_CONFIG_MAP_PROD_DATA = """ + dummy.property.profile=prod + dummy.property.value=3 + dummy.property.enabled=true + """; + + private static final String TEST_CONFIG_MAP_PROPERTIES = "test-cm.properties"; + + private static final String TEST_CONFIG_MAP_NAME = "configmap.test-cm.default.default"; + + private static final String TEST_CONFIG_MAP_DATA = """ + dummy.property.profile=default + dummy.property.value=4 + dummy.property.enabled=true + """; + + private static final String TEST_SECRET_NAME = "secret.test-cm.default.default"; + @Autowired private TestRestTemplate testRestTemplate; @@ -51,23 +101,18 @@ abstract class ConfigServerIntegration { @BeforeEach void beforeEach() { - V1ConfigMapList TEST_CONFIGMAP = new V1ConfigMapList().addItemsItem(new V1ConfigMapBuilder().withMetadata( - new V1ObjectMetaBuilder().withName("test-cm").withNamespace("default").withResourceVersion("1").build()) - .addToData("test-cm-dev.yaml", "dummy:\n property:\n string2: \"dev\"\n int2: 1\n bool2: false\n") - .addToData("test-cm-qa.yaml", "dummy:\n property:\n string2: \"qa\"\n int2: 2\n bool2: true\n") - .addToData("test-cm-prod.yaml", - "dummy:\n property:\n string2: \"prod\"\n int2: 3\n bool2: true\n") - .addToData("test-cm.yaml", "dummy:\n property:\n string2: \"default\"\n int2: 4\n bool2: true\n") + V1ConfigMapList TEST_CONFIGMAP = new V1ConfigMapList().addItemsItem(new V1ConfigMapBuilder() + .withMetadata(new V1ObjectMetaBuilder().withName(SOURCE_NAME).withNamespace(NAMESPACE).build()) + .addToData(TEST_CONFIG_MAP_DEV_PROPERTIES, TEST_CONFIG_MAP_DEV_DATA) + .addToData(TEST_CONFIG_MAP_QA_PROPERTIES, TEST_CONFIG_MAP_QA_DATA) + .addToData(TEST_CONFIG_MAP_PROD_PROPERTIES, TEST_CONFIG_MAP_PROD_DATA) + .addToData(TEST_CONFIG_MAP_PROPERTIES, TEST_CONFIG_MAP_DATA) .addToData("app.name", "test") .build()); - V1SecretList TEST_SECRET = new V1SecretListBuilder() - .withMetadata(new V1ListMetaBuilder().withResourceVersion("1").build()) + V1SecretList TEST_SECRET = new V1SecretListBuilder().withMetadata(new V1ListMetaBuilder().build()) .addToItems(new V1SecretBuilder() - .withMetadata(new V1ObjectMetaBuilder().withName("test-cm") - .withResourceVersion("0") - .withNamespace("default") - .build()) + .withMetadata(new V1ObjectMetaBuilder().withName(SOURCE_NAME).withNamespace(NAMESPACE).build()) .addToData("password", "p455w0rd".getBytes()) .addToData("username", "user".getBytes()) .build()) @@ -80,38 +125,87 @@ void beforeEach() { .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(TEST_SECRET)))); } + @AfterEach + void afterEach() { + WireMock.reset(); + WireMock.shutdownServer(); + wireMockServer.stop(); + wireMockServer.shutdownServer(); + + new KubernetesClientConfigMapsCache().discardAll(); + new KubernetesClientSecretsCache().discardAll(); + } + @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 devprod = testRestTemplate.getForObject("/test-cm/dev,prod", Environment.class); - assertThat(devprod.getPropertySources().size()).isEqualTo(4); - assertThat(devprod.getPropertySources().get(0).getName().equals("configmap.test-cm.default.prod")).isTrue(); - assertThat(devprod.getPropertySources().get(0).getSource().size()).isEqualTo(3); - assertThat(devprod.getPropertySources().get(0).getSource().get("dummy.property.int2")).isEqualTo(3); - assertThat(devprod.getPropertySources().get(0).getSource().get("dummy.property.bool2")).isEqualTo(true); - assertThat(devprod.getPropertySources().get(0).getSource().get("dummy.property.string2")).isEqualTo("prod"); - assertThat(devprod.getPropertySources().get(1).getName().equals("configmap.test-cm.default.dev")).isTrue(); - assertThat(devprod.getPropertySources().get(1).getSource().size()).isEqualTo(3); - assertThat(devprod.getPropertySources().get(1).getSource().get("dummy.property.int2")).isEqualTo(1); - assertThat(devprod.getPropertySources().get(1).getSource().get("dummy.property.bool2")).isEqualTo(false); - assertThat(devprod.getPropertySources().get(1).getSource().get("dummy.property.string2")).isEqualTo("dev"); - assertThat(devprod.getPropertySources().get(2).getName().equals("configmap.test-cm.default.default")).isTrue(); - assertThat(devprod.getPropertySources().get(2).getSource().size()).isEqualTo(4); - assertThat(devprod.getPropertySources().get(2).getSource().get("app.name")).isEqualTo("test"); - assertThat(devprod.getPropertySources().get(2).getSource().get("dummy.property.int2")).isEqualTo(4); - assertThat(devprod.getPropertySources().get(2).getSource().get("dummy.property.bool2")).isEqualTo(true); - assertThat(devprod.getPropertySources().get(2).getSource().get("dummy.property.string2")).isEqualTo("default"); - 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"); + Environment defaultEnv = testRestTemplate.getForObject("/test-cm/default", Environment.class); + assertDefaultProfile(defaultEnv); + + Environment devAndProd = testRestTemplate.getForObject("/test-cm/dev,prod", Environment.class); + assertThat(devAndProd.getPropertySources().size()).isEqualTo(4); + + assertTestConfigMapProd(devAndProd); + assertTestConfigMapDev(devAndProd); + assertTestConfigMapDefault(devAndProd); + assertTestSecretDefault(devAndProd); + + } + + private void assertTestConfigMapDev(Environment devAndProd) { + PropertySource testConfigMapDev = devAndProd.getPropertySources().get(1); + assertThat(testConfigMapDev.getName()).isEqualTo(TEST_CONFIG_MAP_DEV_NAME); + + @SuppressWarnings("unchecked") + Map data = (Map) testConfigMapDev.getSource(); + assertThat(data).containsExactlyInAnyOrderEntriesOf(Map.of("dummy.property.value", "1", + "dummy.property.enabled", "false", "dummy.property.profile", "dev")); + } + + private void assertTestConfigMapProd(Environment devAndProd) { + PropertySource testConfigMapProd = devAndProd.getPropertySources().get(0); + assertThat(testConfigMapProd.getName()).isEqualTo(TEST_CONFIG_MAP_PROD_NAME); + + @SuppressWarnings("unchecked") + 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 testConfigMap = devAndProd.getPropertySources().get(2); + assertThat(testConfigMap.getName()).isEqualTo(TEST_CONFIG_MAP_NAME); + + @SuppressWarnings("unchecked") + Map data = (Map) testConfigMap.getSource(); + assertThat(data).containsExactlyInAnyOrderEntriesOf(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")); } } diff --git a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/resources/META-INF/spring.factories b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/resources/META-INF/spring.factories index b3e57fd872..615b13bb14 100644 --- a/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/resources/META-INF/spring.factories +++ b/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configserver/src/test/resources/META-INF/spring.factories @@ -1,2 +1,3 @@ org.springframework.cloud.bootstrap.BootstrapConfiguration=\ -org.springframework.cloud.kubernetes.configserver.TestBootstrapConfig +org.springframework.cloud.kubernetes.configserver.configurations.FirstConfig,\ +org.springframework.cloud.kubernetes.configserver.configurations.SecondConfig