11/*
2- * Copyright 2013-2020 the original author or authors.
2+ * Copyright 2013-2025 the original author or authors.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
1616
1717package org .springframework .cloud .kubernetes .configuration .watcher ;
1818
19- import java .net .SocketTimeoutException ;
20- import java .time .Duration ;
19+ import java .util .List ;
2120
22- import com .github .tomakehurst .wiremock .client .WireMock ;
23- import io .kubernetes .client .openapi .models .V1ConfigMap ;
24- import io .kubernetes .client .openapi .models .V1ConfigMapBuilder ;
2521import io .kubernetes .client .openapi .models .V1Deployment ;
22+ import io .kubernetes .client .openapi .models .V1EnvVar ;
2623import io .kubernetes .client .openapi .models .V1Service ;
2724import org .junit .jupiter .api .AfterAll ;
2825import org .junit .jupiter .api .AfterEach ;
29- import org .junit .jupiter .api .Assertions ;
3026import org .junit .jupiter .api .BeforeAll ;
3127import org .junit .jupiter .api .BeforeEach ;
3228import org .junit .jupiter .api .Test ;
33- import org .testcontainers .containers .Container ;
3429import org .testcontainers .k3s .K3sContainer ;
3530
3631import org .springframework .cloud .kubernetes .integration .tests .commons .Commons ;
3732import org .springframework .cloud .kubernetes .integration .tests .commons .Images ;
3833import org .springframework .cloud .kubernetes .integration .tests .commons .Phase ;
3934import org .springframework .cloud .kubernetes .integration .tests .commons .native_client .Util ;
4035
41- import static org .awaitility .Awaitility .await ;
36+ import static org .springframework .cloud .kubernetes .configuration .watcher .TestUtil .SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME ;
37+ import static org .springframework .cloud .kubernetes .configuration .watcher .TestUtil .configureWireMock ;
38+ import static org .springframework .cloud .kubernetes .configuration .watcher .TestUtil .createConfigMap ;
39+ import static org .springframework .cloud .kubernetes .configuration .watcher .TestUtil .deleteConfigMap ;
40+ import static org .springframework .cloud .kubernetes .configuration .watcher .TestUtil .verifyActuatorCalled ;
4241
4342/**
4443 * @author Ryan Baxter
4544 */
4645class ActuatorRefreshIT {
4746
48- private static final String SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME = "spring-cloud-kubernetes-configuration-watcher" ;
49-
50- private static final String WIREMOCK_HOST = "localhost" ;
51-
5247 private static final String WIREMOCK_PATH = "/" ;
5348
54- private static final int WIREMOCK_PORT = 80 ;
55-
5649 private static final String NAMESPACE = "default" ;
5750
58- private static final String DOCKER_IMAGE = "docker.io/springcloud/" + SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME + ":"
59- + Commons .pomVersion ();
60-
6151 private static final K3sContainer K3S = Commons .container ();
6252
6353 private static Util util ;
@@ -67,7 +57,6 @@ static void beforeAll() throws Exception {
6757 K3S .start ();
6858 Commons .validateImage (SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME , K3S );
6959 Commons .loadSpringCloudKubernetesImage (SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME , K3S );
70-
7160 Images .loadWiremock (K3S );
7261
7362 util = new Util (K3S );
@@ -92,155 +81,45 @@ void after() {
9281 }
9382
9483 /*
95- * this test loads uses two services: wiremock on port 8080 and configuration-watcher
96- * on port 8888. we deploy configuration-watcher first and configure it via a
97- * configmap with the same name. then , we mock the call to actuator/refresh endpoint
98- * and deploy a new configmap: "service-wiremock", this in turn will trigger that
84+ * This test loads two services: wiremock on port 8080 and configuration-watcher on
85+ * port 8888. We deploy configuration-watcher first and configure its env variables
86+ * that we need for this test. Then , we mock the call to actuator/refresh endpoint and
87+ * deploy a new configmap: "service-wiremock". Because This in turn will trigger a
9988 * refresh that we capture and assert for.
10089 */
101- // curl <WIREMOCK_POD_IP>:8080/__admin/mappings
10290 @ Test
10391 void testActuatorRefresh () {
104-
105- WireMock .configureFor (WIREMOCK_HOST , WIREMOCK_PORT );
106- await ().timeout (Duration .ofSeconds (60 ))
107- .ignoreException (SocketTimeoutException .class )
108- .until (() -> WireMock
109- .stubFor (WireMock .post (WireMock .urlEqualTo ("/actuator/refresh" ))
110- .willReturn (WireMock .aResponse ().withBody ("{}" ).withStatus (200 )))
111- .getResponse ()
112- .wasConfigured ());
113-
114- createConfigMap ();
115-
116- // Wait a bit before we verify
117- await ().atMost (Duration .ofSeconds (30 ))
118- .until (() -> !WireMock .findAll (WireMock .postRequestedFor (WireMock .urlEqualTo ("/actuator/refresh" )))
119- .isEmpty ());
120- WireMock .verify (WireMock .postRequestedFor (WireMock .urlEqualTo ("/actuator/refresh" )));
121-
122- deleteConfigMap ();
123-
124- // the other test
125- testActuatorRefreshReloadDisabled ();
126-
127- }
128-
129- void testActuatorShutdown () {
130- TestUtil .patchForShutdownRefresh (SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME , NAMESPACE , DOCKER_IMAGE );
131- WireMock .configureFor (WIREMOCK_HOST , WIREMOCK_PORT );
132- await ().timeout (Duration .ofSeconds (60 ))
133- .ignoreException (SocketTimeoutException .class )
134- .until (() -> WireMock
135- .stubFor (WireMock .post (WireMock .urlEqualTo ("/actuator/shutdown" ))
136- .willReturn (WireMock .aResponse ().withBody ("{}" ).withStatus (200 )))
137- .getResponse ()
138- .wasConfigured ());
139-
140- createConfigMap ();
141-
142- // Wait a bit before we verify
143- await ().atMost (Duration .ofSeconds (30 ))
144- .until (() -> !WireMock .findAll (WireMock .postRequestedFor (WireMock .urlEqualTo ("/actuator/shutdown" )))
145- .isEmpty ());
146- WireMock .verify (WireMock .postRequestedFor (WireMock .urlEqualTo ("/actuator/shutdown" )));
147-
148- deleteConfigMap ();
149-
150- // the other test
151- testActuatorRefreshReloadDisabled ();
152-
153- }
154-
155- /*
156- * same test as above, but reload is disabled.
157- */
158- void testActuatorRefreshReloadDisabled () {
159-
160- TestUtil .patchForDisabledReload (SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME , NAMESPACE , DOCKER_IMAGE );
161-
162- WireMock .configureFor (WIREMOCK_HOST , WIREMOCK_PORT );
163- await ().timeout (Duration .ofSeconds (60 ))
164- .until (() -> WireMock
165- .stubFor (WireMock .post (WireMock .urlEqualTo ("/actuator/refresh" ))
166- .willReturn (WireMock .aResponse ().withBody ("{}" ).withStatus (200 )))
167- .getResponse ()
168- .wasConfigured ());
169-
170- createConfigMap ();
171-
172- // Wait a bit before we verify
173- await ().atMost (Duration .ofSeconds (30 ))
174- .until (() -> !WireMock .findAll (WireMock .postRequestedFor (WireMock .urlEqualTo ("/actuator/refresh" )))
175- .isEmpty ());
92+ configureWireMock ();
93+ createConfigMap (util , NAMESPACE );
94+ verifyActuatorCalled (1 );
17695
17796 Commons .waitForLogStatement ("creating NOOP strategy because reload is disabled" , K3S ,
17897 SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME );
17998
180- // nothing related to 'ConfigReloadUtil' is present in logs
181- // this proves that once we disable reload everything still works
182- Assertions .assertFalse (logs ().contains ("ConfigReloadUtil" ));
183- WireMock .verify (WireMock .postRequestedFor (WireMock .urlEqualTo ("/actuator/refresh" )));
184-
185- deleteConfigMap ();
186-
99+ deleteConfigMap (util , NAMESPACE );
187100 }
188101
189102 private static void configWatcher (Phase phase ) {
190- V1ConfigMap configMap = (V1ConfigMap ) util
191- .yaml ("config-watcher/spring-cloud-kubernetes-configuration-watcher-configmap.yaml" );
192103 V1Deployment deployment = (V1Deployment ) util
193104 .yaml ("config-watcher/spring-cloud-kubernetes-configuration-watcher-deployment.yaml" );
194105 V1Service service = (V1Service ) util
195106 .yaml ("config-watcher/spring-cloud-kubernetes-configuration-watcher-service.yaml" );
196107
108+ List <V1EnvVar > envVars = List .of (
109+ new V1EnvVar ().name ("SPRING_CLOUD_KUBERNETES_CONFIGURATION_WATCHER_REFRESHDELAY" ).value ("0" ),
110+ new V1EnvVar ().name ("SPRING_CLOUD_KUBERNETES_RELOAD_ENABLED" ).value ("FALSE" ),
111+ new V1EnvVar ().name ("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CONFIGURATION_WATCHER" )
112+ .value ("DEBUG" ));
113+
114+ deployment .getSpec ().getTemplate ().getSpec ().getContainers ().get (0 ).setEnv (envVars );
115+
197116 if (phase .equals (Phase .CREATE )) {
198- util .createAndWait (NAMESPACE , configMap , null );
199117 util .createAndWait (NAMESPACE , null , deployment , service , null , true );
200118 }
201119 else {
202- util .deleteAndWait (NAMESPACE , configMap , null );
203120 util .deleteAndWait (NAMESPACE , deployment , service , null );
204121 }
205122
206123 }
207124
208- // Create new configmap to trigger controller to signal app to refresh
209- private void createConfigMap () {
210- V1ConfigMap configMap = new V1ConfigMapBuilder ().editOrNewMetadata ()
211- .withName ("service-wiremock" )
212- .addToLabels ("spring.cloud.kubernetes.config" , "true" )
213- .endMetadata ()
214- .addToData ("foo" , "bar" )
215- .build ();
216- util .createAndWait (NAMESPACE , configMap , null );
217- }
218-
219- private void deleteConfigMap () {
220- V1ConfigMap configMap = new V1ConfigMapBuilder ().editOrNewMetadata ()
221- .withName ("service-wiremock" )
222- .addToLabels ("spring.cloud.kubernetes.config" , "true" )
223- .endMetadata ()
224- .addToData ("foo" , "bar" )
225- .build ();
226- util .deleteAndWait (NAMESPACE , configMap , null );
227- }
228-
229- private String logs () {
230- try {
231- String appPodName = K3S
232- .execInContainer ("sh" , "-c" ,
233- "kubectl get pods -l app=" + SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME
234- + " -o=name --no-headers | tr -d '\n '" )
235- .getStdout ();
236-
237- Container .ExecResult execResult = K3S .execInContainer ("sh" , "-c" , "kubectl logs " + appPodName .trim ());
238- return execResult .getStdout ();
239- }
240- catch (Exception e ) {
241- e .printStackTrace ();
242- throw new RuntimeException (e );
243- }
244- }
245-
246125}
0 commit comments