1919import  java .util .List ;
2020import  java .util .Optional ;
2121
22+ import  io .reactivex .rxjava3 .core .Completable ;
23+ import  io .reactivex .rxjava3 .core .Flowable ;
24+ import  io .reactivex .rxjava3 .core .Single ;
2225import  org .junit .jupiter .api .Test ;
26+ import  reactor .core .publisher .Flux ;
27+ import  reactor .core .publisher .Mono ;
28+ import  reactor .test .StepVerifier ;
2329
2430import  org .springframework .core .ParameterizedTypeReference ;
31+ import  org .springframework .http .HttpEntity ;
2532import  org .springframework .http .HttpHeaders ;
2633import  org .springframework .http .HttpMethod ;
2734import  org .springframework .http .MediaType ;
3643import  static  org .springframework .http .MediaType .APPLICATION_JSON_VALUE ;
3744
3845/** 
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} . 
4148 * 
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. 
4652 * 
4753 * @author Rossen Stoyanchev 
4854 * @author Olga Maciaszek-Sharma 
4955 */ 
50- abstract   class  HttpServiceMethodTests  {
56+ class  HttpServiceMethodTests  {
5157
52- 	protected  static  final  ParameterizedTypeReference <String > BODY_TYPE  = new  ParameterizedTypeReference <>() {
53- 	};
58+ 	private  static  final  ParameterizedTypeReference <String > BODY_TYPE  = new  ParameterizedTypeReference <>() {};
5459
55- 	protected  TestExchangeAdapter  client ;
5660
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+ 
5871
5972	@ Test 
60- 	void  blockingService () {
61- 		BlockingService  service  = this .proxyFactory .createClient (BlockingService .class );
73+ 	void  service () {
74+ 		Service  service  = this .proxyFactory .createClient (Service .class );
6275
6376		service .execute ();
6477
6578		HttpHeaders  headers  = service .getHeaders ();
6679		assertThat (headers ).isNotNull ();
6780
6881		String  body  = service .getBody ();
69- 		assertThat (body ).isEqualTo (client .getInvokedMethodName ());
82+ 		assertThat (body ).isEqualTo (this . client .getInvokedMethodName ());
7083
7184		Optional <String > optional  = service .getBodyOptional ();
72- 		assertThat (optional .get ()).startsWith ("exchangeForBody" );
85+ 		assertThat (optional .get ()).isEqualTo ("exchangeForBody" );
7386
7487		ResponseEntity <String > entity  = service .getEntity ();
75- 		assertThat (entity .getBody ()).startsWith ("exchangeForEntity" );
88+ 		assertThat (entity .getBody ()).isEqualTo ("exchangeForEntity" );
7689
7790		ResponseEntity <Void > voidEntity  = service .getVoidEntity ();
7891		assertThat (voidEntity .getBody ()).isNull ();
7992
8093		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" );
82158	}
83159
84160	@ Test 
@@ -128,13 +204,14 @@ void typeAndMethodAnnotatedService() {
128204		assertThat (requestValues .getHeaders ().getAccept ()).containsExactly (MediaType .APPLICATION_JSON );
129205	}
130206
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 );
134210	}
135211
212+ 
136213	@ SuppressWarnings ("unused" )
137- 	private  interface  BlockingService  {
214+ 	private  interface  Service  {
138215
139216		@ GetExchange 
140217		void  execute ();
@@ -159,6 +236,64 @@ private interface BlockingService {
159236
160237	}
161238
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+ 
162297	@ SuppressWarnings ("unused" )
163298	private  interface  MethodLevelAnnotatedService  {
164299
@@ -173,7 +308,6 @@ private interface MethodLevelAnnotatedService {
173308	@ SuppressWarnings ("unused" )
174309	@ HttpExchange (url  = "${baseUrl}" , contentType  = APPLICATION_CBOR_VALUE , accept  = APPLICATION_CBOR_VALUE )
175310	private  interface  TypeAndMethodLevelAnnotatedService  extends  MethodLevelAnnotatedService  {
176- 
177311	}
178312
179313}
0 commit comments