28
28
import java .util .List ;
29
29
import java .util .Map ;
30
30
import java .util .Objects ;
31
+ import java .util .concurrent .CompletionException ;
31
32
import java .util .concurrent .TimeUnit ;
32
33
import java .util .stream .Collectors ;
33
34
import java .util .stream .Stream ;
76
77
* @author Eko Kurniawan Khannedy
77
78
* @author Olga Maciaszek-Sharma
78
79
* @author Ilia Ilinykh
80
+ * @author Nguyen Ky Thanh
79
81
*/
80
82
@ SuppressWarnings ("FieldMayBeFinal" )
81
83
@ RunWith (SpringJUnit4ClassRunner .class )
@@ -142,62 +144,124 @@ public FooClient fooClient() {
142
144
"http://localhost:" + port );
143
145
}
144
146
147
+ public FooAsyncClient fooAsyncClient () {
148
+ fooFactoryBean .setApplicationContext (applicationContext );
149
+ return (FooAsyncClient ) fooFactoryBean .asyncFeign (context )
150
+ .target (FooAsyncClient .class , "http://localhost:" + port );
151
+ }
152
+
145
153
public BarClient barClient () {
146
154
barFactoryBean .setApplicationContext (applicationContext );
147
155
return barFactoryBean .feign (context ).target (BarClient .class ,
148
156
"http://localhost:" + port );
149
157
}
150
158
159
+ public BarAsyncClient barAsyncClient () {
160
+ barFactoryBean .setApplicationContext (applicationContext );
161
+ return (BarAsyncClient ) barFactoryBean .asyncFeign (context )
162
+ .target (BarAsyncClient .class , "http://localhost:" + port );
163
+ }
164
+
151
165
public UnwrapClient unwrapClient () {
152
166
unwrapFactoryBean .setApplicationContext (applicationContext );
153
167
return unwrapFactoryBean .feign (context ).target (UnwrapClient .class ,
154
168
"http://localhost:" + port );
155
169
}
156
170
171
+ public UnwrapAsyncClient unwrapAsyncClient () {
172
+ unwrapFactoryBean .setApplicationContext (applicationContext );
173
+ return (UnwrapAsyncClient ) unwrapFactoryBean .asyncFeign (context )
174
+ .target (UnwrapAsyncClient .class , "http://localhost:" + port );
175
+ }
176
+
157
177
public FormClient formClient () {
158
178
formFactoryBean .setApplicationContext (applicationContext );
159
179
return formFactoryBean .feign (context ).target (FormClient .class ,
160
180
"http://localhost:" + port );
161
181
}
162
182
183
+ public FormAsyncClient formAsyncClient () {
184
+ formFactoryBean .setApplicationContext (applicationContext );
185
+ return (FormAsyncClient ) formFactoryBean .asyncFeign (context )
186
+ .target (FormAsyncClient .class , "http://localhost:" + port );
187
+ }
188
+
163
189
@ Test
164
190
public void testFoo () {
165
191
String response = fooClient ().foo ();
166
192
assertThat (response ).isEqualTo ("OK" );
167
193
}
168
194
195
+ @ Test
196
+ public void testFooAsync () {
197
+ String response = fooAsyncClient ().foo ();
198
+ assertThat (response ).isEqualTo ("OK" );
199
+ }
200
+
169
201
@ Test (expected = RetryableException .class )
170
202
public void testBar () {
171
203
barClient ().bar ();
172
204
fail ("it should timeout" );
173
205
}
174
206
207
+ @ Test (expected = CompletionException .class )
208
+ public void testBarAsync () {
209
+ barAsyncClient ().bar ();
210
+ fail ("it should timeout" );
211
+ }
212
+
175
213
@ Test (expected = SocketTimeoutException .class )
176
214
public void testUnwrap () throws Exception {
177
215
unwrapClient ().unwrap ();
178
216
fail ("it should timeout" );
179
217
}
180
218
219
+ @ Test (expected = CompletionException .class )
220
+ public void testUnwrapAsync () throws Exception {
221
+ unwrapAsyncClient ().unwrap ();
222
+ fail ("it should timeout" );
223
+ }
224
+
181
225
@ Test
182
226
public void testForm () {
183
227
Map <String , String > request = Collections .singletonMap ("form" , "Data" );
184
228
String response = formClient ().form (request );
185
229
assertThat (response ).isEqualTo ("Data" );
186
230
}
187
231
232
+ @ Test
233
+ public void testAsyncForm () {
234
+ Map <String , String > request = Collections .singletonMap ("form" , "Data" );
235
+ String response = formAsyncClient ().form (request );
236
+ assertThat (response ).isEqualTo ("Data" );
237
+ }
238
+
188
239
@ Test
189
240
public void testSingleValue () {
190
241
List <String > response = singleValueClient ().singleValue ();
191
242
assertThat (response ).isEqualTo (Arrays .asList ("header" , "parameter" ));
192
243
}
193
244
245
+ @ Test
246
+ public void testSingleValueAsync () {
247
+ List <String > response = singleValueAsyncClient ().singleValue ();
248
+ assertThat (response ).isEqualTo (Arrays .asList ("header" , "parameter" ));
249
+ }
250
+
194
251
@ Test
195
252
public void testMultipleValue () {
196
253
List <String > response = multipleValueClient ().multipleValue ();
197
254
assertThat (response ).isEqualTo (
198
255
Arrays .asList ("header1" , "header2" , "parameter1" , "parameter2" ));
199
256
}
200
257
258
+ @ Test
259
+ public void testMultipleValueAsync () {
260
+ List <String > response = multipleValueAsyncClient ().multipleValue ();
261
+ assertThat (response ).isEqualTo (
262
+ Arrays .asList ("header1" , "header2" , "parameter1" , "parameter2" ));
263
+ }
264
+
201
265
public SingleValueClient singleValueClient () {
202
266
this .defaultHeadersAndQuerySingleParamsFeignClientFactoryBean
203
267
.setApplicationContext (this .applicationContext );
@@ -206,6 +270,14 @@ public SingleValueClient singleValueClient() {
206
270
.target (SingleValueClient .class , "http://localhost:" + this .port );
207
271
}
208
272
273
+ public SingleValueAsyncClient singleValueAsyncClient () {
274
+ this .defaultHeadersAndQuerySingleParamsFeignClientFactoryBean
275
+ .setApplicationContext (this .applicationContext );
276
+ return (SingleValueAsyncClient ) this .defaultHeadersAndQuerySingleParamsFeignClientFactoryBean
277
+ .asyncFeign (this .context )
278
+ .target (SingleValueAsyncClient .class , "http://localhost:" + this .port );
279
+ }
280
+
209
281
public MultipleValueClient multipleValueClient () {
210
282
this .defaultHeadersAndQueryMultipleParamsFeignClientFactoryBean
211
283
.setApplicationContext (this .applicationContext );
@@ -214,6 +286,14 @@ public MultipleValueClient multipleValueClient() {
214
286
.target (MultipleValueClient .class , "http://localhost:" + this .port );
215
287
}
216
288
289
+ public MultipleValueAsyncClient multipleValueAsyncClient () {
290
+ this .defaultHeadersAndQueryMultipleParamsFeignClientFactoryBean
291
+ .setApplicationContext (this .applicationContext );
292
+ return (MultipleValueAsyncClient ) this .defaultHeadersAndQueryMultipleParamsFeignClientFactoryBean
293
+ .asyncFeign (this .context )
294
+ .target (MultipleValueAsyncClient .class , "http://localhost:" + this .port );
295
+ }
296
+
217
297
@ Test
218
298
public void readTimeoutShouldWorkWhenConnectTimeoutNotSet () {
219
299
FeignClientFactoryBean readTimeoutFactoryBean = new FeignClientFactoryBean ();
@@ -230,6 +310,23 @@ public void readTimeoutShouldWorkWhenConnectTimeoutNotSet() {
230
310
assertThat (options .connectTimeoutMillis ()).isEqualTo (5000 );
231
311
}
232
312
313
+ @ Test
314
+ public void readTimeoutAsyncShouldWorkWhenConnectTimeoutNotSet () {
315
+ FeignClientFactoryBean readTimeoutFactoryBean = new FeignClientFactoryBean ();
316
+ readTimeoutFactoryBean .setContextId ("readTimeout" );
317
+ readTimeoutFactoryBean .setType (FeignClientFactoryBean .class );
318
+ readTimeoutFactoryBean .setApplicationContext (applicationContext );
319
+
320
+ TimeoutAsyncClient client = (TimeoutAsyncClient ) readTimeoutFactoryBean
321
+ .asyncFeign (context )
322
+ .target (TimeoutAsyncClient .class , "http://localhost:" + port );
323
+
324
+ Request .Options options = getAsyncRequestOptions ((Proxy ) client );
325
+
326
+ assertThat (options .readTimeoutMillis ()).isEqualTo (1000 );
327
+ assertThat (options .connectTimeoutMillis ()).isEqualTo (5000 );
328
+ }
329
+
233
330
@ Test
234
331
public void connectTimeoutShouldWorkWhenReadTimeoutNotSet () {
235
332
FeignClientFactoryBean readTimeoutFactoryBean = new FeignClientFactoryBean ();
@@ -246,6 +343,23 @@ public void connectTimeoutShouldWorkWhenReadTimeoutNotSet() {
246
343
assertThat (options .readTimeoutMillis ()).isEqualTo (5000 );
247
344
}
248
345
346
+ @ Test
347
+ public void connectTimeoutAsyncShouldWorkWhenReadTimeoutNotSet () {
348
+ FeignClientFactoryBean readTimeoutFactoryBean = new FeignClientFactoryBean ();
349
+ readTimeoutFactoryBean .setContextId ("connectTimeout" );
350
+ readTimeoutFactoryBean .setType (FeignClientFactoryBean .class );
351
+ readTimeoutFactoryBean .setApplicationContext (applicationContext );
352
+
353
+ TimeoutAsyncClient client = (TimeoutAsyncClient ) readTimeoutFactoryBean
354
+ .asyncFeign (context )
355
+ .target (TimeoutAsyncClient .class , "http://localhost:" + port );
356
+
357
+ Request .Options options = getAsyncRequestOptions ((Proxy ) client );
358
+
359
+ assertThat (options .connectTimeoutMillis ()).isEqualTo (1000 );
360
+ assertThat (options .readTimeoutMillis ()).isEqualTo (5000 );
361
+ }
362
+
249
363
@ Test
250
364
public void shouldSetFollowRedirects () {
251
365
FeignClientFactoryBean testFactoryBean = new FeignClientFactoryBean ();
@@ -261,6 +375,22 @@ public void shouldSetFollowRedirects() {
261
375
assertThat (options .isFollowRedirects ()).isFalse ();
262
376
}
263
377
378
+ @ Test
379
+ public void shouldSetFollowRedirectsAsync () {
380
+ FeignClientFactoryBean testFactoryBean = new FeignClientFactoryBean ();
381
+ testFactoryBean .setContextId ("test" );
382
+ testFactoryBean .setType (FeignClientFactoryBean .class );
383
+ testFactoryBean .setApplicationContext (applicationContext );
384
+
385
+ TimeoutAsyncClient client = (TimeoutAsyncClient ) testFactoryBean
386
+ .asyncFeign (context )
387
+ .target (TimeoutAsyncClient .class , "http://localhost:" + port );
388
+
389
+ Request .Options options = getAsyncRequestOptions ((Proxy ) client );
390
+
391
+ assertThat (options .isFollowRedirects ()).isFalse ();
392
+ }
393
+
264
394
private Request .Options getRequestOptions (Proxy client ) {
265
395
Object invocationHandler = ReflectionTestUtils .getField (client , "h" );
266
396
Map <Method , InvocationHandlerFactory .MethodHandler > dispatch = (Map <Method , InvocationHandlerFactory .MethodHandler >) ReflectionTestUtils
@@ -270,27 +400,60 @@ private Request.Options getRequestOptions(Proxy client) {
270
400
"options" );
271
401
}
272
402
403
+ private Request .Options getAsyncRequestOptions (Proxy client ) {
404
+ Object asyncInvocationHandler = ReflectionTestUtils .getField (client , "h" );
405
+ Object instance = ReflectionTestUtils .getField (asyncInvocationHandler ,
406
+ "instance" );
407
+ Object invocationHandler = ReflectionTestUtils .getField (instance , "h" );
408
+ Map <Method , InvocationHandlerFactory .MethodHandler > dispatch = (Map <Method , InvocationHandlerFactory .MethodHandler >) ReflectionTestUtils
409
+ .getField (Objects .requireNonNull (invocationHandler ), "dispatch" );
410
+ Method key = new ArrayList <>(dispatch .keySet ()).get (0 );
411
+ return (Request .Options ) ReflectionTestUtils .getField (dispatch .get (key ),
412
+ "options" );
413
+ }
414
+
273
415
protected interface FooClient {
274
416
275
417
@ GetMapping (path = "/foo" )
276
418
String foo ();
277
419
278
420
}
279
421
422
+ protected interface FooAsyncClient {
423
+
424
+ @ GetMapping (path = "/foo" )
425
+ String foo ();
426
+
427
+ }
428
+
280
429
protected interface BarClient {
281
430
282
431
@ GetMapping (path = "/bar" )
283
432
String bar ();
284
433
285
434
}
286
435
436
+ protected interface BarAsyncClient {
437
+
438
+ @ GetMapping (path = "/bar" )
439
+ String bar ();
440
+
441
+ }
442
+
287
443
protected interface UnwrapClient {
288
444
289
445
@ GetMapping (path = "/bar" ) // intentionally /bar
290
446
String unwrap () throws IOException ;
291
447
292
448
}
293
449
450
+ protected interface UnwrapAsyncClient {
451
+
452
+ @ GetMapping (path = "/bar" ) // intentionally /bar
453
+ String unwrap () throws IOException ;
454
+
455
+ }
456
+
294
457
protected interface FormClient {
295
458
296
459
@ RequestMapping (value = "/form" , method = RequestMethod .POST ,
@@ -299,27 +462,56 @@ protected interface FormClient {
299
462
300
463
}
301
464
465
+ protected interface FormAsyncClient {
466
+
467
+ @ RequestMapping (value = "/form" , method = RequestMethod .POST ,
468
+ consumes = MediaType .APPLICATION_FORM_URLENCODED_VALUE )
469
+ String form (Map <String , String > form );
470
+
471
+ }
472
+
302
473
protected interface SingleValueClient {
303
474
304
475
@ GetMapping (path = "/singleValue" )
305
476
List <String > singleValue ();
306
477
307
478
}
308
479
480
+ protected interface SingleValueAsyncClient {
481
+
482
+ @ GetMapping (path = "/singleValue" )
483
+ List <String > singleValue ();
484
+
485
+ }
486
+
309
487
protected interface MultipleValueClient {
310
488
311
489
@ GetMapping (path = "/multipleValue" )
312
490
List <String > multipleValue ();
313
491
314
492
}
315
493
494
+ protected interface MultipleValueAsyncClient {
495
+
496
+ @ GetMapping (path = "/multipleValue" )
497
+ List <String > multipleValue ();
498
+
499
+ }
500
+
316
501
protected interface TimeoutClient {
317
502
318
503
@ GetMapping ("/timeouts" )
319
504
String timeouts ();
320
505
321
506
}
322
507
508
+ protected interface TimeoutAsyncClient {
509
+
510
+ @ GetMapping ("/timeouts" )
511
+ String timeouts ();
512
+
513
+ }
514
+
323
515
@ Configuration (proxyBeanMethods = false )
324
516
@ EnableAutoConfiguration
325
517
@ RestController
0 commit comments