2121import java .util .List ;
2222import java .util .Map ;
2323import java .util .Set ;
24+ import java .util .concurrent .atomic .AtomicBoolean ;
2425import java .util .stream .Collectors ;
2526
2627import com .github .tomakehurst .wiremock .WireMockServer ;
2728import com .github .tomakehurst .wiremock .client .WireMock ;
29+ import com .github .tomakehurst .wiremock .stubbing .Scenario ;
2830import io .kubernetes .client .openapi .ApiClient ;
2931import io .kubernetes .client .openapi .Configuration ;
3032import io .kubernetes .client .openapi .JSON ;
6163import org .springframework .mock .env .MockEnvironment ;
6264
6365import static com .github .tomakehurst .wiremock .client .WireMock .aResponse ;
66+ import static com .github .tomakehurst .wiremock .client .WireMock .equalTo ;
6467import static com .github .tomakehurst .wiremock .client .WireMock .get ;
6568import static com .github .tomakehurst .wiremock .client .WireMock .stubFor ;
69+ import static com .github .tomakehurst .wiremock .client .WireMock .urlPathMatching ;
6670import static com .github .tomakehurst .wiremock .core .WireMockConfiguration .options ;
6771
6872/**
@@ -83,7 +87,11 @@ class EventReloadSecretTest {
8387
8488 private static final String NAMESPACE = "spring-k8s" ;
8589
86- private static final boolean [] strategyCalled = new boolean [] { false };
90+ private static final String PATH = "/api/v1/namespaces/spring-k8s/secrets" ;
91+
92+ private static final String SCENARIO_NAME = "reload-test" ;
93+
94+ private static final AtomicBoolean STRATEGY_CALLED = new AtomicBoolean (false );
8795
8896 private static CoreV1Api coreV1Api ;
8997
@@ -100,6 +108,12 @@ static void setup() {
100108 wireMockServer .start ();
101109 WireMock .configureFor ("localhost" , wireMockServer .port ());
102110
111+ // something that the informer can work with. Since we do not care about this one
112+ // in the test, we mock it to return a 500 as it does not matter anyway.
113+ stubFor (get (urlPathMatching (PATH )).withQueryParam ("resourceVersion" , equalTo ("0" ))
114+ .withQueryParam ("watch" , equalTo ("false" ))
115+ .willReturn (aResponse ().withStatus (500 ).withBody ("Error From Informer" )));
116+
103117 ApiClient client = new ClientBuilder ().setBasePath ("http://localhost:" + wireMockServer .port ()).build ();
104118 client .setDebugging (true );
105119 MOCK_STATIC .when (KubernetesClientUtils ::createApiClientForInformerClient ).thenReturn (client );
@@ -109,30 +123,6 @@ static void setup() {
109123 .thenReturn (NAMESPACE );
110124 Configuration .setDefaultApiClient (client );
111125 coreV1Api = new CoreV1Api ();
112-
113- String path = "/api/v1/namespaces/spring-k8s/secrets" ;
114- V1Secret secretOne = secret (SECRET_NAME , Map .of ());
115- V1SecretList listOne = new V1SecretList ().addItemsItem (secretOne );
116-
117- // needed so that our environment is populated with 'something'
118- // this call is done in the method that returns the AbstractEnvironment
119- stubFor (get (path ).willReturn (aResponse ().withStatus (200 ).withBody (new JSON ().serialize (listOne )))
120- .inScenario ("mine-test" )
121- .willSetStateTo ("go-to-fail" ));
122-
123- // first call will fail
124- stubFor (get (path ).willReturn (aResponse ().withStatus (500 ).withBody ("Internal Server Error" ))
125- .inScenario ("mine-test" )
126- .whenScenarioStateIs ("go-to-fail" )
127- .willSetStateTo ("go-to-ok" ));
128-
129- // second call passes (change data so that reload is triggered)
130- secretOne = secret (SECRET_NAME , Map .of ("a" , "b" ));
131- listOne = new V1SecretList ().addItemsItem (secretOne );
132- stubFor (get (path ).willReturn (aResponse ().withStatus (200 ).withBody (new JSON ().serialize (listOne )))
133- .inScenario ("mine-test" )
134- .whenScenarioStateIs ("go-to-ok" )
135- .willSetStateTo ("done" ));
136126 }
137127
138128 @ AfterAll
@@ -151,6 +141,12 @@ static void after() {
151141 */
152142 @ Test
153143 void test (CapturedOutput output ) {
144+ // first call will fail
145+ stubFor (get (PATH ).willReturn (aResponse ().withStatus (500 ).withBody ("Internal Server Error" ))
146+ .inScenario (SCENARIO_NAME )
147+ .whenScenarioStateIs ("go-to-fail" )
148+ .willSetStateTo ("go-to-ok" ));
149+
154150 V1Secret secretNotMine = secret ("not" + SECRET_NAME , Map .of ());
155151 kubernetesClientEventBasedSecretsChangeDetector .onEvent (secretNotMine );
156152
@@ -160,17 +156,25 @@ void test(CapturedOutput output) {
160156 boolean two = output .getOut ().contains ("Failed to load source" );
161157 boolean three = output .getOut ()
162158 .contains ("Reloadable condition was not satisfied, reload will not be triggered" );
163- boolean updateStrategyNotCalled = !strategyCalled [ 0 ] ;
159+ boolean updateStrategyNotCalled = !STRATEGY_CALLED . get () ;
164160 return one && two && three && updateStrategyNotCalled ;
165161 });
166162
163+ // second call passes (change data so that reload is triggered)
164+ V1Secret secret = secret (SECRET_NAME , Map .of ("a" , "b" ));
165+ V1SecretList secretList = new V1SecretList ().addItemsItem (secret );
166+ stubFor (get (PATH ).willReturn (aResponse ().withStatus (200 ).withBody (new JSON ().serialize (secretList )))
167+ .inScenario (SCENARIO_NAME )
168+ .whenScenarioStateIs ("go-to-ok" )
169+ .willSetStateTo ("done" ));
170+
167171 // trigger the call again
168172 V1Secret secretMine = secret (SECRET_NAME , Map .of ());
169173 kubernetesClientEventBasedSecretsChangeDetector .onEvent (secretMine );
170174 Awaitility .await ()
171175 .atMost (Duration .ofSeconds (10 ))
172176 .pollInterval (Duration .ofSeconds (1 ))
173- .until (() -> strategyCalled [ 0 ] );
177+ .until (STRATEGY_CALLED :: get );
174178 }
175179
176180 private static V1Secret secret (String name , Map <String , String > data ) {
@@ -199,6 +203,17 @@ VisibleKubernetesClientEventBasedSecretsChangeDetector kubernetesClientEventBase
199203 @ Bean
200204 @ Primary
201205 AbstractEnvironment environment () {
206+
207+ // needed so that our environment is populated with 'something'
208+ // this call is done in the method that returns the AbstractEnvironment
209+ V1Secret secret = secret (SECRET_NAME , Map .of ());
210+ V1SecretList secretList = new V1SecretList ().addItemsItem (secret );
211+
212+ stubFor (get (PATH ).willReturn (aResponse ().withStatus (200 ).withBody (new JSON ().serialize (secretList )))
213+ .inScenario (SCENARIO_NAME )
214+ .whenScenarioStateIs (Scenario .STARTED )
215+ .willSetStateTo ("go-to-fail" ));
216+
202217 MockEnvironment mockEnvironment = new MockEnvironment ();
203218 mockEnvironment .setProperty ("spring.cloud.kubernetes.client.namespace" , NAMESPACE );
204219
@@ -221,7 +236,7 @@ AbstractEnvironment environment() {
221236 @ Primary
222237 ConfigReloadProperties configReloadProperties () {
223238 return new ConfigReloadProperties (true , true , false , ConfigReloadProperties .ReloadStrategy .REFRESH ,
224- ConfigReloadProperties .ReloadDetectionMode .POLLING , Duration .ofMillis (2000 ), Set .of ("non-default " ),
239+ ConfigReloadProperties .ReloadDetectionMode .POLLING , Duration .ofMillis (2000 ), Set .of ("spring-k8s " ),
225240 false , Duration .ofSeconds (2 ));
226241 }
227242
@@ -242,7 +257,7 @@ KubernetesNamespaceProvider namespaceProvider(AbstractEnvironment environment) {
242257 @ Primary
243258 ConfigurationUpdateStrategy configurationUpdateStrategy () {
244259 return new ConfigurationUpdateStrategy ("to-console" , () -> {
245- strategyCalled [ 0 ] = true ;
260+ STRATEGY_CALLED . set ( true ) ;
246261 });
247262 }
248263
0 commit comments