3434
3535import java .io .IOException ;
3636import java .net .SocketTimeoutException ;
37+ import java .util .concurrent .CancellationException ;
3738import java .util .concurrent .CountDownLatch ;
3839import java .util .concurrent .ExecutionException ;
3940import java .util .concurrent .Future ;
4748import static com .github .tomakehurst .wiremock .client .WireMock .delete ;
4849import static com .github .tomakehurst .wiremock .client .WireMock .deleteRequestedFor ;
4950import static com .github .tomakehurst .wiremock .client .WireMock .equalTo ;
51+ import static com .github .tomakehurst .wiremock .client .WireMock .exactly ;
5052import static com .github .tomakehurst .wiremock .client .WireMock .get ;
5153import static com .github .tomakehurst .wiremock .client .WireMock .getRequestedFor ;
5254import static com .github .tomakehurst .wiremock .client .WireMock .patch ;
5961import static com .github .tomakehurst .wiremock .client .WireMock .urlEqualTo ;
6062import static com .github .tomakehurst .wiremock .client .WireMock .urlPathEqualTo ;
6163import static com .github .tomakehurst .wiremock .client .WireMock .verify ;
64+ import static com .github .tomakehurst .wiremock .core .WireMockConfiguration .wireMockConfig ;
6265import static org .junit .Assert .assertEquals ;
6366import static org .junit .Assert .assertFalse ;
6467import static org .junit .Assert .assertNull ;
6871
6972public class GenericKubernetesApiForCoreApiTest {
7073
71- @ Rule public WireMockRule wireMockRule = new WireMockRule (8181 );
74+ @ Rule public WireMockRule wireMockRule = new WireMockRule (wireMockConfig (). dynamicPort () );
7275
73- private JSON json = new JSON ();
76+ private final JSON json = new JSON ();
7477 private GenericKubernetesApi <V1Pod , V1PodList > podClient ;
7578
7679 @ Before
7780 public void setup () throws IOException {
78- ApiClient apiClient = new ClientBuilder ().setBasePath ("http://localhost:" + 8181 ).build ();
81+ ApiClient apiClient = new ClientBuilder ().setBasePath ("http://localhost:" + wireMockRule . port () ).build ();
7982 apiClient .setHttpClient (apiClient .getHttpClient ().newBuilder ().addInterceptor (new TestInterceptor ()).build ());
8083 podClient =
8184 new GenericKubernetesApi <>(V1Pod .class , V1PodList .class , "" , "v1" , "pods" , apiClient );
@@ -174,7 +177,7 @@ public void listClusterPodAsyncReturningObject() throws InterruptedException, Ex
174177 assertFalse (podListFuture .isDone ());
175178 assertFalse (podListFuture .isCancelled ());
176179
177- assertThrows (TimeoutException .class , () -> podListFuture .get (1 , TimeUnit .SECONDS ));
180+ assertThrows (TimeoutException .class , () -> podListFuture .get (10 , TimeUnit .MILLISECONDS ));
178181
179182 waitForRequest .proceed ();
180183
@@ -190,6 +193,42 @@ public void listClusterPodAsyncReturningObject() throws InterruptedException, Ex
190193 getRequestedFor (urlPathEqualTo ("/api/v1/pods" )).withQueryParam ("watch" , equalTo ("false" )));
191194 }
192195
196+ @ Test
197+ public void listClusterPodAsyncCanceled () {
198+ V1PodList podList = new V1PodList ().kind ("PodList" ).metadata (new V1ListMeta ());
199+
200+ stubFor (
201+ get (urlPathEqualTo ("/api/v1/pods" ))
202+ .willReturn (aResponse ().withStatus (200 ).withBody (json .serialize (podList ))));
203+ TestCallback <V1PodList > callback = new TestCallback <>(podClient .getApiClient ());
204+
205+ // request will be blocked until proceed()
206+ WaitForRequest waitForRequest = callback .awaitBeforeRequest ();
207+
208+ Future <KubernetesApiResponse <V1PodList >> podListFuture = podClient .listAsync (callback );
209+
210+ assertFalse (podListFuture .isDone ());
211+ assertFalse (podListFuture .isCancelled ());
212+
213+ // cancel request
214+ assertTrue (podListFuture .cancel (true ));
215+
216+ assertTrue (podListFuture .isCancelled ());
217+ assertTrue (podListFuture .isDone ());
218+
219+ // unblock thread to clean up
220+ waitForRequest .proceed ();
221+
222+ assertThrows (CancellationException .class , podListFuture ::get );
223+ assertThrows (CancellationException .class , () -> podListFuture .get (10 , TimeUnit .MILLISECONDS ));
224+
225+ assertFalse (callback .hasBeenCalled ());
226+
227+ verify (
228+ exactly (0 ),
229+ getRequestedFor (urlPathEqualTo ("/api/v1/pods" )).withQueryParam ("watch" , equalTo ("false" )));
230+ }
231+
193232 @ Test
194233 public void createNamespacedPodReturningObject () {
195234 V1Pod foo1 =
@@ -257,7 +296,7 @@ public void patchNamespacedPodWithApiPrefix() {
257296 "" ,
258297 "v1" ,
259298 "pods" ,
260- new ClientBuilder ().setBasePath ("http://localhost:" + 8181 + prefix ).build ());
299+ new ClientBuilder ().setBasePath ("http://localhost:" + wireMockRule . port () + prefix ).build ());
261300 KubernetesApiResponse <V1Pod > podPatchResp =
262301 rancherPodClient .patch (
263302 "default" , "foo1" , V1Patch .PATCH_FORMAT_STRATEGIC_MERGE_PATCH , v1Patch );
@@ -270,7 +309,7 @@ public void patchNamespacedPodWithApiPrefix() {
270309
271310 @ Test
272311 public void testReadTimeoutShouldThrowException () {
273- ApiClient apiClient = new ClientBuilder ().setBasePath ("http://localhost:" + 8181 ).build ();
312+ ApiClient apiClient = new ClientBuilder ().setBasePath ("http://localhost:" + wireMockRule . port () ).build ();
274313 apiClient .setHttpClient (
275314 apiClient
276315 .getHttpClient ()
@@ -299,11 +338,6 @@ static class TestCallback<ApiType extends KubernetesType>
299338 final ApiClient apiClient ;
300339
301340 WaitForRequest waitForRequest = null ;
302- WaitForResponse waitForResponse = null ;
303-
304- TestCallback () {
305- this (null );
306- }
307341
308342 TestCallback (ApiClient apiClient ) {
309343 this .apiClient = apiClient ;
@@ -320,26 +354,21 @@ public KubernetesApiResponse<ApiType> waitForAndGetResponse() throws Interrupted
320354 return result .get ();
321355 }
322356
357+ public boolean hasBeenCalled () {
358+ return latch .getCount () == 0 ;
359+ }
360+
323361 public WaitForRequest awaitBeforeRequest () {
324362 waitForRequest = new WaitForRequest ();
325363 return waitForRequest ;
326364 }
327365
328- public WaitForResponse awaitBeforeResponse () {
329- waitForResponse = new WaitForResponse ();
330- return waitForResponse ;
331- }
332-
333366 @ Override
334367 public Call apply (Call call ) {
335368 if (waitForRequest != null ) {
336369 call = apiClient .getHttpClient ().newCall (
337370 call .request ().newBuilder ().tag (WaitForRequest .class , waitForRequest ).build ());
338371 }
339- if (waitForResponse != null ) {
340- call = apiClient .getHttpClient ().newCall (
341- call .request ().newBuilder ().tag (WaitForResponse .class , waitForResponse ).build ());
342- }
343372 return call ;
344373 }
345374 }
@@ -351,9 +380,6 @@ static class TestInterceptor implements Interceptor {
351380 public Response intercept (@ NotNull Chain chain ) throws IOException {
352381 final Request request = chain .request ();
353382
354- // TEST
355- System .out .println ("Before proceed" );
356-
357383 WaitForRequest waitForRequest = request .tag (WaitForRequest .class );
358384 if (waitForRequest != null ) {
359385 try {
@@ -363,25 +389,11 @@ public Response intercept(@NotNull Chain chain) throws IOException {
363389 }
364390 }
365391
366- final Response response = chain .proceed (request );
367-
368- // TEST
369- System .out .println ("After proceed" );
370-
371- WaitForResponse waitForResponse = request .tag (WaitForResponse .class );
372- if (waitForResponse != null ) {
373- try {
374- waitForResponse .await ();
375- } catch (InterruptedException e ) {
376- throw new IOException (e );
377- }
378- }
379-
380- return response ;
392+ return chain .proceed (request );
381393 }
382394 }
383395
384- static class WaitSignal {
396+ static class WaitForRequest {
385397 final CountDownLatch latch = new CountDownLatch (1 );
386398
387399 public void await () throws InterruptedException {
@@ -392,12 +404,4 @@ public void proceed() {
392404 latch .countDown ();
393405 }
394406 }
395-
396- static class WaitForRequest extends WaitSignal {
397-
398- }
399-
400- static class WaitForResponse extends WaitSignal {
401-
402- }
403407}
0 commit comments