19
19
import java .util .List ;
20
20
import java .util .Optional ;
21
21
22
+ import io .reactivex .rxjava3 .core .Completable ;
23
+ import io .reactivex .rxjava3 .core .Flowable ;
24
+ import io .reactivex .rxjava3 .core .Single ;
22
25
import org .junit .jupiter .api .Test ;
26
+ import reactor .core .publisher .Flux ;
27
+ import reactor .core .publisher .Mono ;
28
+ import reactor .test .StepVerifier ;
23
29
24
30
import org .springframework .core .ParameterizedTypeReference ;
31
+ import org .springframework .http .HttpEntity ;
25
32
import org .springframework .http .HttpHeaders ;
26
33
import org .springframework .http .HttpMethod ;
27
34
import org .springframework .http .MediaType ;
36
43
import static org .springframework .http .MediaType .APPLICATION_JSON_VALUE ;
37
44
38
45
/**
39
- * Base class for testing {@link HttpServiceMethod} with a test {@link TestExchangeAdapter}
40
- * and a test {@link TestExchangeAdapter} that stub the client invocations .
46
+ * Tests for {@link HttpServiceMethod} with
47
+ * {@link TestExchangeAdapter} and {@link TestReactorExchangeAdapter} .
41
48
*
42
- * <p>
43
- * The tests do not create or invoke {@code HttpServiceMethod} directly but rather use
44
- * {@link HttpServiceProxyFactory} to create a service proxy in order to use a strongly
45
- * typed interface without the need for class casts.
49
+ * <p>The tests do not create or invoke {@code HttpServiceMethod} directly but
50
+ * rather use {@link HttpServiceProxyFactory} to create a service proxy in order to
51
+ * use a strongly typed interface without the need for class casts.
46
52
*
47
53
* @author Rossen Stoyanchev
48
54
* @author Olga Maciaszek-Sharma
49
55
*/
50
- abstract class HttpServiceMethodTests {
56
+ class HttpServiceMethodTests {
51
57
52
- protected static final ParameterizedTypeReference <String > BODY_TYPE = new ParameterizedTypeReference <>() {
53
- };
58
+ private static final ParameterizedTypeReference <String > BODY_TYPE = new ParameterizedTypeReference <>() {};
54
59
55
- protected TestExchangeAdapter client ;
56
60
57
- protected HttpServiceProxyFactory proxyFactory ;
61
+ private final TestExchangeAdapter client = new TestExchangeAdapter ();
62
+
63
+ private final TestReactorExchangeAdapter reactorClient = new TestReactorExchangeAdapter ();
64
+
65
+ private final HttpServiceProxyFactory proxyFactory =
66
+ HttpServiceProxyFactory .builder ().exchangeAdapter (this .client ).build ();
67
+
68
+ private final HttpServiceProxyFactory reactorProxyFactory =
69
+ HttpServiceProxyFactory .builder ().exchangeAdapter (this .reactorClient ).build ();
70
+
58
71
59
72
@ Test
60
- void blockingService () {
61
- BlockingService service = this .proxyFactory .createClient (BlockingService .class );
73
+ void service () {
74
+ Service service = this .proxyFactory .createClient (Service .class );
62
75
63
76
service .execute ();
64
77
65
78
HttpHeaders headers = service .getHeaders ();
66
79
assertThat (headers ).isNotNull ();
67
80
68
81
String body = service .getBody ();
69
- assertThat (body ).isEqualTo (client .getInvokedMethodName ());
82
+ assertThat (body ).isEqualTo (this . client .getInvokedMethodName ());
70
83
71
84
Optional <String > optional = service .getBodyOptional ();
72
- assertThat (optional .get ()).startsWith ("exchangeForBody" );
85
+ assertThat (optional .get ()).isEqualTo ("exchangeForBody" );
73
86
74
87
ResponseEntity <String > entity = service .getEntity ();
75
- assertThat (entity .getBody ()).startsWith ("exchangeForEntity" );
88
+ assertThat (entity .getBody ()).isEqualTo ("exchangeForEntity" );
76
89
77
90
ResponseEntity <Void > voidEntity = service .getVoidEntity ();
78
91
assertThat (voidEntity .getBody ()).isNull ();
79
92
80
93
List <String > list = service .getList ();
81
- assertThat (list .get (0 )).startsWith ("exchangeForBody" );
94
+ assertThat (list .get (0 )).isEqualTo ("exchangeForBody" );
95
+ }
96
+
97
+ @ Test
98
+ void reactorService () {
99
+ ReactorService service = this .reactorProxyFactory .createClient (ReactorService .class );
100
+
101
+ Mono <Void > voidMono = service .execute ();
102
+ StepVerifier .create (voidMono ).verifyComplete ();
103
+ verifyReactorClientInvocation ("exchangeForMono" , null );
104
+
105
+ Mono <HttpHeaders > headersMono = service .getHeaders ();
106
+ StepVerifier .create (headersMono ).expectNextCount (1 ).verifyComplete ();
107
+ verifyReactorClientInvocation ("exchangeForHeadersMono" , null );
108
+
109
+ Mono <String > body = service .getBody ();
110
+ StepVerifier .create (body ).expectNext ("exchangeForBodyMono" ).verifyComplete ();
111
+ verifyReactorClientInvocation ("exchangeForBodyMono" , BODY_TYPE );
112
+
113
+ Flux <String > fluxBody = service .getFluxBody ();
114
+ StepVerifier .create (fluxBody ).expectNext ("exchange" , "For" , "Body" , "Flux" ).verifyComplete ();
115
+ verifyReactorClientInvocation ("exchangeForBodyFlux" , BODY_TYPE );
116
+
117
+ Mono <ResponseEntity <Void >> voidEntity = service .getVoidEntity ();
118
+ StepVerifier .create (voidEntity ).expectNext (ResponseEntity .ok ().build ()).verifyComplete ();
119
+ verifyReactorClientInvocation ("exchangeForBodilessEntityMono" , null );
120
+
121
+ Mono <ResponseEntity <String >> entity = service .getEntity ();
122
+ StepVerifier .create (entity ).expectNext (ResponseEntity .ok ("exchangeForEntityMono" ));
123
+ verifyReactorClientInvocation ("exchangeForEntityMono" , BODY_TYPE );
124
+
125
+ Mono <ResponseEntity <Flux <String >>> fluxEntity = service .getFluxEntity ();
126
+ StepVerifier .create (fluxEntity .flatMapMany (HttpEntity ::getBody ))
127
+ .expectNext ("exchange" , "For" , "Entity" , "Flux" )
128
+ .verifyComplete ();
129
+ verifyReactorClientInvocation ("exchangeForEntityFlux" , BODY_TYPE );
130
+
131
+ assertThat (service .getDefaultMethodValue ()).isEqualTo ("default value" );
132
+ }
133
+
134
+ @ Test
135
+ void rxJavaService () {
136
+ RxJavaService service = this .reactorProxyFactory .createClient (RxJavaService .class );
137
+ Completable completable = service .execute ();
138
+ assertThat (completable ).isNotNull ();
139
+
140
+ Single <HttpHeaders > headersSingle = service .getHeaders ();
141
+ assertThat (headersSingle .blockingGet ()).isNotNull ();
142
+
143
+ Single <String > bodySingle = service .getBody ();
144
+ assertThat (bodySingle .blockingGet ()).isEqualTo ("exchangeForBodyMono" );
145
+
146
+ Flowable <String > bodyFlow = service .getFlowableBody ();
147
+ assertThat (bodyFlow .toList ().blockingGet ()).asList ().containsExactly ("exchange" , "For" , "Body" , "Flux" );
148
+
149
+ Single <ResponseEntity <Void >> voidEntity = service .getVoidEntity ();
150
+ assertThat (voidEntity .blockingGet ().getBody ()).isNull ();
151
+
152
+ Single <ResponseEntity <String >> entitySingle = service .getEntity ();
153
+ assertThat (entitySingle .blockingGet ().getBody ()).isEqualTo ("exchangeForEntityMono" );
154
+
155
+ Single <ResponseEntity <Flowable <String >>> entityFlow = service .getFlowableEntity ();
156
+ Flowable <String > body = (entityFlow .blockingGet ()).getBody ();
157
+ assertThat (body .toList ().blockingGet ()).containsExactly ("exchange" , "For" , "Entity" , "Flux" );
82
158
}
83
159
84
160
@ Test
@@ -128,13 +204,14 @@ void typeAndMethodAnnotatedService() {
128
204
assertThat (requestValues .getHeaders ().getAccept ()).containsExactly (MediaType .APPLICATION_JSON );
129
205
}
130
206
131
- protected void verifyClientInvocation (String methodName , @ Nullable ParameterizedTypeReference <?> expectedBodyType ) {
132
- assertThat (this .client .getInvokedMethodName ()).isEqualTo (methodName );
133
- assertThat (this .client .getBodyType ()).isEqualTo (expectedBodyType );
207
+ protected void verifyReactorClientInvocation (String methodName , @ Nullable ParameterizedTypeReference <?> expectedBodyType ) {
208
+ assertThat (this .reactorClient .getInvokedMethodName ()).isEqualTo (methodName );
209
+ assertThat (this .reactorClient .getBodyType ()).isEqualTo (expectedBodyType );
134
210
}
135
211
212
+
136
213
@ SuppressWarnings ("unused" )
137
- private interface BlockingService {
214
+ private interface Service {
138
215
139
216
@ GetExchange
140
217
void execute ();
@@ -159,6 +236,64 @@ private interface BlockingService {
159
236
160
237
}
161
238
239
+
240
+ private interface ReactorService {
241
+
242
+ @ GetExchange
243
+ Mono <Void > execute ();
244
+
245
+ @ GetExchange
246
+ Mono <HttpHeaders > getHeaders ();
247
+
248
+ @ GetExchange
249
+ Mono <String > getBody ();
250
+
251
+ @ GetExchange
252
+ Flux <String > getFluxBody ();
253
+
254
+ @ GetExchange
255
+ Mono <ResponseEntity <Void >> getVoidEntity ();
256
+
257
+ @ GetExchange
258
+ Mono <ResponseEntity <String >> getEntity ();
259
+
260
+ @ GetExchange
261
+ Mono <ResponseEntity <Flux <String >>> getFluxEntity ();
262
+
263
+ default String getDefaultMethodValue () {
264
+ return "default value" ;
265
+ }
266
+
267
+ }
268
+
269
+
270
+ @ SuppressWarnings ("unused" )
271
+ private interface RxJavaService {
272
+
273
+ @ GetExchange
274
+ Completable execute ();
275
+
276
+ @ GetExchange
277
+ Single <HttpHeaders > getHeaders ();
278
+
279
+ @ GetExchange
280
+ Single <String > getBody ();
281
+
282
+ @ GetExchange
283
+ Flowable <String > getFlowableBody ();
284
+
285
+ @ GetExchange
286
+ Single <ResponseEntity <Void >> getVoidEntity ();
287
+
288
+ @ GetExchange
289
+ Single <ResponseEntity <String >> getEntity ();
290
+
291
+ @ GetExchange
292
+ Single <ResponseEntity <Flowable <String >>> getFlowableEntity ();
293
+
294
+ }
295
+
296
+
162
297
@ SuppressWarnings ("unused" )
163
298
private interface MethodLevelAnnotatedService {
164
299
@@ -173,7 +308,6 @@ private interface MethodLevelAnnotatedService {
173
308
@ SuppressWarnings ("unused" )
174
309
@ HttpExchange (url = "${baseUrl}" , contentType = APPLICATION_CBOR_VALUE , accept = APPLICATION_CBOR_VALUE )
175
310
private interface TypeAndMethodLevelAnnotatedService extends MethodLevelAnnotatedService {
176
-
177
311
}
178
312
179
313
}
0 commit comments