Skip to content

Commit 47667ab

Browse files
committed
Collapse hierarchy under HttpServiceMethodTests
See gh-30117
1 parent 068dc7d commit 47667ab

File tree

4 files changed

+156
-266
lines changed

4 files changed

+156
-266
lines changed

spring-web/src/test/java/org/springframework/web/service/invoker/HttpExchangeAdapterServiceMethodTests.java

-39
This file was deleted.

spring-web/src/test/java/org/springframework/web/service/invoker/HttpServiceMethodTests.java

+156-22
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,16 @@
1919
import java.util.List;
2020
import 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;
2225
import org.junit.jupiter.api.Test;
26+
import reactor.core.publisher.Flux;
27+
import reactor.core.publisher.Mono;
28+
import reactor.test.StepVerifier;
2329

2430
import org.springframework.core.ParameterizedTypeReference;
31+
import org.springframework.http.HttpEntity;
2532
import org.springframework.http.HttpHeaders;
2633
import org.springframework.http.HttpMethod;
2734
import org.springframework.http.MediaType;
@@ -36,49 +43,118 @@
3643
import 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

Comments
 (0)