diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload_it/EventReloadConfigMapTest.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload_it/EventReloadConfigMapTest.java index 1c72fd36a..d01eface1 100644 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload_it/EventReloadConfigMapTest.java +++ b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload_it/EventReloadConfigMapTest.java @@ -24,6 +24,7 @@ import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.stubbing.Scenario; import io.kubernetes.client.openapi.ApiClient; import io.kubernetes.client.openapi.Configuration; import io.kubernetes.client.openapi.JSON; @@ -82,6 +83,10 @@ class EventReloadConfigMapTest { private static final String NAMESPACE = "spring-k8s"; + private static final String SCENARIO_NAME = "reload-test"; + + private static final String PATH = "/api/v1/namespaces/spring-k8s/configmaps"; + private static final AtomicBoolean STRATEGY_CALLED = new AtomicBoolean(false); private static CoreV1Api coreV1Api; @@ -109,29 +114,15 @@ static void setup() { Configuration.setDefaultApiClient(client); coreV1Api = new CoreV1Api(); - String path = "/api/v1/namespaces/spring-k8s/configmaps"; - V1ConfigMap configMapOne = configMap(CONFIG_MAP_NAME, Map.of()); - V1ConfigMapList listOne = new V1ConfigMapList().addItemsItem(configMapOne); + V1ConfigMap configMap = configMap(CONFIG_MAP_NAME, Map.of()); + V1ConfigMapList configMapList = new V1ConfigMapList().addItemsItem(configMap); // needed so that our environment is populated with 'something' // this call is done in the method that returns the AbstractEnvironment - stubFor(get(path).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(listOne))) - .inScenario("mine-test") + stubFor(get(PATH).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(configMapList))) + .inScenario(SCENARIO_NAME) + .whenScenarioStateIs(Scenario.STARTED) .willSetStateTo("go-to-fail")); - - // first call will fail - stubFor(get(path).willReturn(aResponse().withStatus(500).withBody("Internal Server Error")) - .inScenario("mine-test") - .whenScenarioStateIs("go-to-fail") - .willSetStateTo("go-to-ok")); - - // second call passes (change data so that reload is triggered) - configMapOne = configMap(CONFIG_MAP_NAME, Map.of("a", "b")); - listOne = new V1ConfigMapList().addItemsItem(configMapOne); - stubFor(get(path).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(listOne))) - .inScenario("mine-test") - .whenScenarioStateIs("go-to-ok") - .willSetStateTo("done")); } @AfterAll @@ -153,6 +144,12 @@ void test(CapturedOutput output) { V1ConfigMap configMapNotMine = configMap("not" + CONFIG_MAP_NAME, Map.of()); kubernetesClientEventBasedConfigMapChangeDetector.onEvent(configMapNotMine); + // first call will fail + stubFor(get(PATH).willReturn(aResponse().withStatus(500).withBody("Internal Server Error")) + .inScenario(SCENARIO_NAME) + .whenScenarioStateIs("go-to-fail") + .willSetStateTo("go-to-ok")); + // we fail while reading 'configMapOne' Awaitility.await().atMost(Duration.ofSeconds(10)).pollInterval(Duration.ofSeconds(1)).until(() -> { boolean one = output.getOut().contains("Failure in reading named sources"); @@ -163,6 +160,14 @@ void test(CapturedOutput output) { return one && two && three && updateStrategyNotCalled; }); + // second call passes (change data so that reload is triggered) + V1ConfigMap configMap = configMap(CONFIG_MAP_NAME, Map.of("a", "b")); + V1ConfigMapList configMapList = new V1ConfigMapList().addItemsItem(configMap); + stubFor(get(PATH).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(configMapList))) + .inScenario(SCENARIO_NAME) + .whenScenarioStateIs("go-to-ok") + .willSetStateTo("done")); + // trigger the call again V1ConfigMap configMapMine = configMap(CONFIG_MAP_NAME, Map.of()); kubernetesClientEventBasedConfigMapChangeDetector.onEvent(configMapMine); diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload_it/EventReloadSecretTest.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload_it/EventReloadSecretTest.java index afe24991c..7687efb59 100644 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload_it/EventReloadSecretTest.java +++ b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload_it/EventReloadSecretTest.java @@ -26,6 +26,7 @@ import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.stubbing.Scenario; import io.kubernetes.client.openapi.ApiClient; import io.kubernetes.client.openapi.Configuration; import io.kubernetes.client.openapi.JSON; @@ -62,8 +63,10 @@ import org.springframework.mock.env.MockEnvironment; import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; import static com.github.tomakehurst.wiremock.client.WireMock.get; import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; /** @@ -78,16 +81,20 @@ class EventReloadSecretTest { private static final boolean FAIL_FAST = false; - private static WireMockServer wireMockServer; - private static final String SECRET_NAME = "mine"; private static final String NAMESPACE = "spring-k8s"; + private static final String PATH = "/api/v1/namespaces/spring-k8s/secrets"; + + private static final String SCENARIO_NAME = "reload-test"; + private static final AtomicBoolean STRATEGY_CALLED = new AtomicBoolean(false); private static CoreV1Api coreV1Api; + private static WireMockServer wireMockServer; + private static final MockedStatic MOCK_STATIC = Mockito .mockStatic(KubernetesClientUtils.class); @@ -111,29 +118,21 @@ static void setup() { Configuration.setDefaultApiClient(client); coreV1Api = new CoreV1Api(); - String path = "/api/v1/namespaces/spring-k8s/secrets"; - V1Secret secretOne = secret(SECRET_NAME, Map.of()); - V1SecretList listOne = new V1SecretList().addItemsItem(secretOne); + V1Secret secret = secret(SECRET_NAME, Map.of()); + V1SecretList secretList = new V1SecretList().addItemsItem(secret); // needed so that our environment is populated with 'something' // this call is done in the method that returns the AbstractEnvironment - stubFor(get(path).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(listOne))) - .inScenario("mine-test") + stubFor(get(PATH) + .willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(secretList))) + .inScenario(SCENARIO_NAME) + .whenScenarioStateIs(Scenario.STARTED) .willSetStateTo("go-to-fail")); - // first call will fail - stubFor(get(path).willReturn(aResponse().withStatus(500).withBody("Internal Server Error")) - .inScenario("mine-test") - .whenScenarioStateIs("go-to-fail") - .willSetStateTo("go-to-ok")); + stubFor(get(urlPathEqualTo(PATH)).withQueryParam("resourceVersion", equalTo("0")) + .withQueryParam("watch", equalTo("false")) + .willReturn(aResponse().withStatus(500).withBody(" he he he"))); - // second call passes (change data so that reload is triggered) - secretOne = secret(SECRET_NAME, Map.of("a", "b")); - listOne = new V1SecretList().addItemsItem(secretOne); - stubFor(get(path).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(listOne))) - .inScenario("mine-test") - .whenScenarioStateIs("go-to-ok") - .willSetStateTo("done")); } @AfterAll @@ -155,6 +154,12 @@ void test(CapturedOutput output) { V1Secret secretNotMine = secret("not" + SECRET_NAME, Map.of()); kubernetesClientEventBasedSecretsChangeDetector.onEvent(secretNotMine); + // first call will fail + stubFor(get(PATH).willReturn(aResponse().withStatus(500).withBody("Internal Server Error")) + .inScenario(SCENARIO_NAME) + .whenScenarioStateIs("go-to-fail") + .willSetStateTo("go-to-ok")); + // we fail while reading 'configMapOne' Awaitility.await().atMost(Duration.ofSeconds(10)).pollInterval(Duration.ofSeconds(1)).until(() -> { boolean one = output.getOut().contains("Failure in reading named sources"); @@ -165,8 +170,16 @@ void test(CapturedOutput output) { return one && two && three && updateStrategyNotCalled; }); + // second call passes (change data so that reload is triggered) + V1Secret secret = secret(SECRET_NAME, Map.of("a", "b")); + V1SecretList secretList = new V1SecretList().addItemsItem(secret); + stubFor(get(PATH).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(secretList))) + .inScenario(SCENARIO_NAME) + .whenScenarioStateIs("go-to-ok") + .willSetStateTo("done")); + // trigger the call again - V1Secret secretMine = secret(SECRET_NAME, Map.of()); + V1Secret secretMine = secret(SECRET_NAME, Map.of("a", "b")); kubernetesClientEventBasedSecretsChangeDetector.onEvent(secretMine); Awaitility.await() .atMost(Duration.ofSeconds(10)) @@ -222,7 +235,7 @@ AbstractEnvironment environment() { @Primary ConfigReloadProperties configReloadProperties() { return new ConfigReloadProperties(true, true, false, ConfigReloadProperties.ReloadStrategy.REFRESH, - ConfigReloadProperties.ReloadDetectionMode.POLLING, Duration.ofMillis(2000), Set.of("non-default"), + ConfigReloadProperties.ReloadDetectionMode.POLLING, Duration.ofMillis(2000), Set.of("spring-k8s"), false, Duration.ofSeconds(2)); } diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload_it/PollingReloadConfigMapTest.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload_it/PollingReloadConfigMapTest.java index a33beb98b..ef956dcdb 100644 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload_it/PollingReloadConfigMapTest.java +++ b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload_it/PollingReloadConfigMapTest.java @@ -24,6 +24,7 @@ import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.stubbing.Scenario; import io.kubernetes.client.openapi.ApiClient; import io.kubernetes.client.openapi.Configuration; import io.kubernetes.client.openapi.JSON; @@ -72,18 +73,22 @@ @ExtendWith(OutputCaptureExtension.class) class PollingReloadConfigMapTest { - private static WireMockServer wireMockServer; - private static final boolean FAIL_FAST = false; private static final String CONFIG_MAP_NAME = "mine"; + private static final String PATH = "/api/v1/namespaces/spring-k8s/configmaps"; + private static final String NAMESPACE = "spring-k8s"; + private static final String SCENARIO_NAME = "reload-test"; + private static final AtomicBoolean STRATEGY_CALLED = new AtomicBoolean(false); private static CoreV1Api coreV1Api; + private static WireMockServer wireMockServer; + @BeforeAll static void setup() { wireMockServer = new WireMockServer(options().dynamicPort()); @@ -96,29 +101,15 @@ static void setup() { Configuration.setDefaultApiClient(client); coreV1Api = new CoreV1Api(); - String path = "/api/v1/namespaces/spring-k8s/configmaps"; V1ConfigMap configMapOne = configMap(CONFIG_MAP_NAME, Map.of()); V1ConfigMapList listOne = new V1ConfigMapList().addItemsItem(configMapOne); // needed so that our environment is populated with 'something' // this call is done in the method that returns the AbstractEnvironment - stubFor(get(path).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(listOne))) - .inScenario("my-test") + stubFor(get(PATH).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(listOne))) + .inScenario(SCENARIO_NAME) + .whenScenarioStateIs(Scenario.STARTED) .willSetStateTo("go-to-fail")); - - // first reload call fails - stubFor(get(path).willReturn(aResponse().withStatus(500).withBody("Internal Server Error")) - .inScenario("my-test") - .whenScenarioStateIs("go-to-fail") - .willSetStateTo("go-to-ok")); - - // second reload call passes - V1ConfigMap configMapTwo = configMap(CONFIG_MAP_NAME, Map.of("a", "b")); - V1ConfigMapList listTwo = new V1ConfigMapList().addItemsItem(configMapTwo); - stubFor(get(path).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(listTwo))) - .inScenario("my-test") - .whenScenarioStateIs("go-to-ok")); - } @AfterAll @@ -135,17 +126,33 @@ static void after() { */ @Test void test(CapturedOutput output) { + + // first reload call fails + stubFor(get(PATH).willReturn(aResponse().withStatus(500).withBody("Internal Server Error")) + .inScenario(SCENARIO_NAME) + .whenScenarioStateIs("go-to-fail") + .willSetStateTo("go-to-ok")); + // we fail while reading 'configMapOne' - Awaitility.await().atMost(Duration.ofSeconds(20)).pollInterval(Duration.ofSeconds(1)).until(() -> { + Awaitility.await().atMost(Duration.ofSeconds(10)).pollInterval(Duration.ofSeconds(1)).until(() -> { boolean one = output.getOut().contains("Failure in reading named sources"); boolean two = output.getOut().contains("Failed to load source"); boolean three = output.getOut() .contains("Reloadable condition was not satisfied, reload will not be triggered"); boolean updateStrategyNotCalled = !STRATEGY_CALLED.get(); - System.out.println("one: " + one + " two: " + two + " three: " + three + " updateStrategyNotCalled: " + updateStrategyNotCalled); + System.out.println("one: " + one + " two: " + two + " three: " + three + " updateStrategyNotCalled: " + + updateStrategyNotCalled); return one && two && three && updateStrategyNotCalled; }); + // second reload call passes + V1ConfigMap configMapTwo = configMap(CONFIG_MAP_NAME, Map.of("a", "b")); + V1ConfigMapList listTwo = new V1ConfigMapList().addItemsItem(configMapTwo); + stubFor(get(PATH).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(listTwo))) + .inScenario(SCENARIO_NAME) + .whenScenarioStateIs("go-to-ok") + .willSetStateTo("done")); + System.out.println("first assertion passed"); // it passes while reading 'configMapTwo' diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload_it/PollingReloadSecretTest.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload_it/PollingReloadSecretTest.java index 4421ca32e..c623165ad 100644 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload_it/PollingReloadSecretTest.java +++ b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/reload_it/PollingReloadSecretTest.java @@ -26,6 +26,7 @@ import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.stubbing.Scenario; import io.kubernetes.client.openapi.ApiClient; import io.kubernetes.client.openapi.Configuration; import io.kubernetes.client.openapi.JSON; @@ -74,18 +75,22 @@ @ExtendWith(OutputCaptureExtension.class) class PollingReloadSecretTest { - private static WireMockServer wireMockServer; - private static final boolean FAIL_FAST = false; private static final String SECRET_NAME = "mine"; + private static final String PATH = "/api/v1/namespaces/spring-k8s/secrets"; + private static final String NAMESPACE = "spring-k8s"; + private static final String SCENARIO_NAME = "reload-test"; + private static final AtomicBoolean STRATEGY_CALLED = new AtomicBoolean(false); private static CoreV1Api coreV1Api; + private static WireMockServer wireMockServer; + @BeforeAll static void setup() { wireMockServer = new WireMockServer(options().dynamicPort()); @@ -98,28 +103,16 @@ static void setup() { Configuration.setDefaultApiClient(client); coreV1Api = new CoreV1Api(); - String path = "/api/v1/namespaces/spring-k8s/secrets"; V1Secret secretOne = secret(SECRET_NAME, Map.of()); V1SecretList listOne = new V1SecretList().addItemsItem(secretOne); // needed so that our environment is populated with 'something' // this call is done in the method that returns the AbstractEnvironment - stubFor(get(path).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(listOne))) - .inScenario("my-test") + stubFor(get(PATH).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(listOne))) + .inScenario(SCENARIO_NAME) + .whenScenarioStateIs(Scenario.STARTED) .willSetStateTo("go-to-fail")); - // first reload call fails - stubFor(get(path).willReturn(aResponse().withStatus(500).withBody("Internal Server Error")) - .inScenario("my-test") - .whenScenarioStateIs("go-to-fail") - .willSetStateTo("go-to-ok")); - - V1Secret secretTwo = secret(SECRET_NAME, Map.of("a", "b")); - V1SecretList listTwo = new V1SecretList().addItemsItem(secretTwo); - stubFor(get(path).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(listTwo))) - .inScenario("my-test") - .whenScenarioStateIs("go-to-ok")); - } @AfterAll @@ -136,8 +129,15 @@ static void after() { */ @Test void test(CapturedOutput output) { + + // first reload call fails + stubFor(get(PATH).willReturn(aResponse().withStatus(500).withBody("Internal Server Error")) + .inScenario(SCENARIO_NAME) + .whenScenarioStateIs("go-to-fail") + .willSetStateTo("go-to-ok")); + // we fail while reading 'secretOne' - Awaitility.await().atMost(Duration.ofSeconds(20)).pollInterval(Duration.ofSeconds(1)).until(() -> { + Awaitility.await().atMost(Duration.ofSeconds(10)).pollInterval(Duration.ofSeconds(1)).until(() -> { boolean one = output.getOut().contains("Failure in reading named sources"); boolean two = output.getOut().contains("Failed to load source"); boolean three = output.getOut() @@ -146,6 +146,13 @@ void test(CapturedOutput output) { return one && two && three && updateStrategyNotCalled; }); + V1Secret secretTwo = secret(SECRET_NAME, Map.of("a", "b")); + V1SecretList listTwo = new V1SecretList().addItemsItem(secretTwo); + stubFor(get(PATH).willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(listTwo))) + .inScenario(SCENARIO_NAME) + .willSetStateTo("done") + .whenScenarioStateIs("go-to-ok")); + // it passes while reading 'secretTwo' Awaitility.await() .atMost(Duration.ofSeconds(20))