Skip to content

Commit 0c3bf14

Browse files
committed
Merge remote-tracking branch 'origin/4.2.x'
2 parents b730ac3 + 64e44ce commit 0c3bf14

File tree

3 files changed

+188
-349
lines changed

3 files changed

+188
-349
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -25,18 +25,14 @@
2525
import java.util.concurrent.ConcurrentHashMap;
2626

2727
import org.junit.jupiter.api.BeforeEach;
28-
import org.junit.jupiter.api.Disabled;
2928
import org.junit.jupiter.api.Test;
29+
import reactor.core.publisher.Mono;
3030

3131
import org.springframework.beans.factory.annotation.Autowired;
32-
import org.springframework.boot.SpringBootConfiguration;
33-
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
34-
import org.springframework.boot.test.context.SpringBootTest;
3532
import org.springframework.boot.test.web.server.LocalServerPort;
3633
import org.springframework.cloud.client.DefaultServiceInstance;
3734
import org.springframework.cloud.client.ServiceInstance;
3835
import org.springframework.cloud.client.discovery.DiscoveryClient;
39-
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
4036
import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryProperties;
4137
import org.springframework.cloud.client.loadbalancer.CompletionContext;
4238
import org.springframework.cloud.client.loadbalancer.DefaultRequestContext;
@@ -45,93 +41,97 @@
4541
import org.springframework.cloud.client.loadbalancer.Request;
4642
import org.springframework.cloud.client.loadbalancer.Response;
4743
import org.springframework.cloud.client.loadbalancer.ResponseData;
48-
import org.springframework.context.annotation.Bean;
44+
import org.springframework.http.HttpMethod;
4945
import org.springframework.http.HttpStatus;
50-
import org.springframework.web.bind.annotation.GetMapping;
51-
import org.springframework.web.bind.annotation.RestController;
52-
import org.springframework.web.reactive.function.client.ClientResponse;
46+
import org.springframework.http.ResponseEntity;
5347
import org.springframework.web.reactive.function.client.WebClient;
5448

5549
import static org.assertj.core.api.Assertions.assertThat;
56-
import static org.assertj.core.api.Assertions.assertThatCode;
50+
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
51+
import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode;
5752
import static org.assertj.core.api.BDDAssertions.then;
58-
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
5953

6054
/**
61-
* Tests for {@link ReactorLoadBalancerExchangeFilterFunction}.
55+
* Base class for {@link LoadBalancedExchangeFilterFunction} integration tests.
6256
*
6357
* @author Olga Maciaszek-Sharma
64-
* @author Charu Covindane
6558
*/
66-
@SuppressWarnings("ConstantConditions")
67-
@SpringBootTest(webEnvironment = RANDOM_PORT)
68-
class ReactorLoadBalancerExchangeFilterFunctionTests {
59+
@SuppressWarnings("DataFlowIssue")
60+
abstract class AbstractLoadBalancerExchangeFilterFunctionIntegrationTests {
6961

7062
@Autowired
71-
private ReactorLoadBalancerExchangeFilterFunction loadBalancerFunction;
63+
protected LoadBalancedExchangeFilterFunction loadBalancerFunction;
7264

7365
@Autowired
74-
private SimpleDiscoveryProperties properties;
66+
protected SimpleDiscoveryProperties properties;
7567

7668
@Autowired
77-
private LoadBalancerProperties loadBalancerProperties;
69+
protected LoadBalancerProperties loadBalancerProperties;
7870

7971
@Autowired
80-
private ReactiveLoadBalancer.Factory<ServiceInstance> factory;
72+
protected ReactiveLoadBalancer.Factory<ServiceInstance> factory;
8173

8274
@LocalServerPort
83-
private int port;
75+
protected int port;
8476

8577
@BeforeEach
86-
void setUp() {
78+
protected void setUp() {
8779
DefaultServiceInstance instance = new DefaultServiceInstance();
8880
instance.setServiceId("testservice");
89-
instance.setUri(URI.create("http://localhost:" + this.port));
81+
instance.setUri(URI.create("http://localhost:" + port));
9082
DefaultServiceInstance instanceWithNoLifecycleProcessors = new DefaultServiceInstance();
9183
instanceWithNoLifecycleProcessors.setServiceId("serviceWithNoLifecycleProcessors");
92-
instanceWithNoLifecycleProcessors.setUri(URI.create("http://localhost:" + this.port));
84+
instanceWithNoLifecycleProcessors.setUri(URI.create("http://localhost:" + port));
9385
properties.getInstances().put("testservice", Collections.singletonList(instance));
9486
properties.getInstances()
9587
.put("serviceWithNoLifecycleProcessors", Collections.singletonList(instanceWithNoLifecycleProcessors));
9688
}
9789

9890
@Test
9991
void correctResponseReturnedForExistingHostAndInstancePresent() {
100-
ClientResponse clientResponse = WebClient.builder()
92+
ResponseEntity<String> response = WebClient.builder()
10193
.baseUrl("http://testservice")
10294
.filter(loadBalancerFunction)
10395
.build()
10496
.get()
10597
.uri("/hello")
106-
.exchange()
98+
.retrieve()
99+
.toEntity(String.class)
107100
.block();
108-
then(clientResponse.statusCode()).isEqualTo(HttpStatus.OK);
109-
then(clientResponse.bodyToMono(String.class).block()).isEqualTo("Hello World");
101+
then(response.getStatusCode()).isEqualTo(HttpStatus.OK);
102+
then(response.getBody()).isEqualTo("Hello World");
110103
}
111104

112105
@Test
113106
void serviceUnavailableReturnedWhenNoInstancePresent() {
114-
ClientResponse clientResponse = WebClient.builder()
115-
.baseUrl("http://xxx")
116-
.filter(this.loadBalancerFunction)
117-
.build()
118-
.get()
119-
.exchange()
120-
.block();
121-
then(clientResponse.statusCode()).isEqualTo(HttpStatus.SERVICE_UNAVAILABLE);
107+
assertThatIllegalStateException()
108+
.isThrownBy(() -> WebClient.builder()
109+
.baseUrl("http://xxx")
110+
.filter(loadBalancerFunction)
111+
.defaultStatusHandler(httpStatusCode -> httpStatusCode.equals(HttpStatus.SERVICE_UNAVAILABLE),
112+
clientResponse -> Mono.just(new IllegalStateException("503")))
113+
.build()
114+
.get()
115+
.retrieve()
116+
.toBodilessEntity()
117+
.block())
118+
.withMessage("503");
122119
}
123120

124121
@Test
125-
@Disabled // FIXME 3.0.0
126122
void badRequestReturnedForIncorrectHost() {
127-
ClientResponse clientResponse = WebClient.builder()
128-
.baseUrl("http:///xxx")
129-
.filter(this.loadBalancerFunction)
130-
.build()
131-
.get()
132-
.exchange()
133-
.block();
134-
then(clientResponse.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
123+
assertThatIllegalStateException()
124+
.isThrownBy(() -> WebClient.builder()
125+
.baseUrl("http:///xxx")
126+
.filter(loadBalancerFunction)
127+
.defaultStatusHandler(httpStatusCode -> httpStatusCode.equals(HttpStatus.BAD_REQUEST),
128+
response -> Mono.just(new IllegalStateException("400")))
129+
.build()
130+
.get()
131+
.retrieve()
132+
.toBodilessEntity()
133+
.block())
134+
.withMessage("400");
135135
}
136136

137137
@Test
@@ -142,97 +142,88 @@ void exceptionNotThrownWhenFactoryReturnsNullLifecycleProcessorsMap() {
142142
.build()
143143
.get()
144144
.uri("/hello")
145-
.exchange()
145+
.exchangeToMono(clientResponse -> clientResponse.bodyToMono(String.class))
146146
.block()).doesNotThrowAnyException();
147147
}
148148

149149
@Test
150150
void loadBalancerLifecycleCallbacksExecuted() {
151151
final String callbackTestHint = "callbackTestHint";
152152
loadBalancerProperties.getHint().put("testservice", "callbackTestHint");
153-
ClientResponse clientResponse = WebClient.builder()
153+
154+
ResponseEntity<Void> response = WebClient.builder()
154155
.baseUrl("http://testservice")
155156
.filter(loadBalancerFunction)
156157
.build()
157158
.get()
158159
.uri("/callback")
159-
.exchange()
160+
.retrieve()
161+
.toBodilessEntity()
160162
.block();
161163

162164
Collection<Request<Object>> lifecycleLogRequests = ((TestLoadBalancerLifecycle) factory
163165
.getInstances("testservice", LoadBalancerLifecycle.class)
164166
.get("loadBalancerLifecycle")).getStartLog().values();
165-
Collection<Request<Object>> lifecycleStartedLogRequests = ((TestLoadBalancerLifecycle) factory
167+
Collection<Request<Object>> lifecycleLogStartRequests = ((TestLoadBalancerLifecycle) factory
166168
.getInstances("testservice", LoadBalancerLifecycle.class)
167169
.get("loadBalancerLifecycle")).getStartRequestLog().values();
168170
Collection<CompletionContext<Object, ServiceInstance, Object>> anotherLifecycleLogRequests = ((AnotherLoadBalancerLifecycle) factory
169171
.getInstances("testservice", LoadBalancerLifecycle.class)
170172
.get("anotherLoadBalancerLifecycle")).getCompleteLog().values();
171-
then(clientResponse.statusCode()).isEqualTo(HttpStatus.OK);
173+
then(response.getStatusCode()).isEqualTo(HttpStatus.OK);
172174
assertThat(lifecycleLogRequests).extracting(request -> ((DefaultRequestContext) request.getContext()).getHint())
173175
.contains(callbackTestHint);
174-
assertThat(lifecycleStartedLogRequests)
176+
assertThat(lifecycleLogStartRequests)
175177
.extracting(request -> ((DefaultRequestContext) request.getContext()).getHint())
176178
.contains(callbackTestHint);
177179
assertThat(anotherLifecycleLogRequests)
178180
.extracting(completionContext -> ((ResponseData) completionContext.getClientResponse()).getRequestData()
179-
.getUrl()
180-
.toString())
181-
.contains("http://testservice/callback");
181+
.getHttpMethod())
182+
.contains(HttpMethod.GET);
182183
}
183184

184-
@SuppressWarnings({ "unchecked", "rawtypes" })
185-
@EnableDiscoveryClient
186-
@EnableAutoConfiguration
187-
@SpringBootConfiguration(proxyBeanMethods = false)
188-
@RestController
189-
static class Config {
185+
protected static class TestLoadBalancerFactory implements ReactiveLoadBalancer.Factory<ServiceInstance> {
186+
187+
private final ReactorLoadBalancerExchangeFilterFunctionIntegrationTests.TestLoadBalancerLifecycle testLoadBalancerLifecycle;
188+
189+
private final ReactorLoadBalancerExchangeFilterFunctionIntegrationTests.TestLoadBalancerLifecycle anotherLoadBalancerLifecycle;
190190

191-
@GetMapping("/hello")
192-
public String hello() {
193-
return "Hello World";
191+
private final DiscoveryClient discoveryClient;
192+
193+
private final LoadBalancerProperties properties;
194+
195+
public TestLoadBalancerFactory(DiscoveryClient discoveryClient, LoadBalancerProperties properties) {
196+
this.discoveryClient = discoveryClient;
197+
this.properties = properties;
198+
testLoadBalancerLifecycle = new ReactorLoadBalancerExchangeFilterFunctionIntegrationTests.TestLoadBalancerLifecycle();
199+
anotherLoadBalancerLifecycle = new ReactorLoadBalancerExchangeFilterFunctionIntegrationTests.AnotherLoadBalancerLifecycle();
194200
}
195201

196-
@GetMapping("/callback")
197-
String callbackTestResult() {
198-
return "callbackTestResult";
202+
@Override
203+
public ReactiveLoadBalancer<ServiceInstance> getInstance(String serviceId) {
204+
return new DiscoveryClientBasedReactiveLoadBalancer(serviceId, discoveryClient);
199205
}
200206

201-
@Bean
202-
ReactiveLoadBalancer.Factory<ServiceInstance> reactiveLoadBalancerFactory(DiscoveryClient discoveryClient,
203-
LoadBalancerProperties properties) {
204-
return new ReactiveLoadBalancer.Factory<>() {
205-
206-
private final TestLoadBalancerLifecycle testLoadBalancerLifecycle = new TestLoadBalancerLifecycle();
207-
208-
private final TestLoadBalancerLifecycle anotherLoadBalancerLifecycle = new AnotherLoadBalancerLifecycle();
209-
210-
@Override
211-
public ReactiveLoadBalancer<ServiceInstance> getInstance(String serviceId) {
212-
return new DiscoveryClientBasedReactiveLoadBalancer(serviceId, discoveryClient);
213-
}
214-
215-
@Override
216-
public <X> Map<String, X> getInstances(String name, Class<X> type) {
217-
if (name.equals("serviceWithNoLifecycleProcessors")) {
218-
return null;
219-
}
220-
Map lifecycleProcessors = new HashMap<>();
221-
lifecycleProcessors.put("loadBalancerLifecycle", testLoadBalancerLifecycle);
222-
lifecycleProcessors.put("anotherLoadBalancerLifecycle", anotherLoadBalancerLifecycle);
223-
return lifecycleProcessors;
224-
}
225-
226-
@Override
227-
public <X> X getInstance(String name, Class<?> clazz, Class<?>... generics) {
228-
return null;
229-
}
230-
231-
@Override
232-
public LoadBalancerProperties getProperties(String serviceId) {
233-
return properties;
234-
}
235-
};
207+
@SuppressWarnings({ "rawtypes", "unchecked" })
208+
@Override
209+
public <X> Map<String, X> getInstances(String name, Class<X> type) {
210+
if (name.equals("serviceWithNoLifecycleProcessors")) {
211+
return null;
212+
}
213+
Map lifecycleProcessors = new HashMap<>();
214+
lifecycleProcessors.put("loadBalancerLifecycle", testLoadBalancerLifecycle);
215+
lifecycleProcessors.put("anotherLoadBalancerLifecycle", anotherLoadBalancerLifecycle);
216+
return lifecycleProcessors;
217+
}
218+
219+
@Override
220+
public <X> X getInstance(String name, Class<?> clazz, Class<?>... generics) {
221+
return null;
222+
}
223+
224+
@Override
225+
public LoadBalancerProperties getProperties(String serviceId) {
226+
return properties;
236227
}
237228

238229
}
@@ -257,6 +248,7 @@ public void onStartRequest(Request<Object> request, Response<ServiceInstance> lb
257248

258249
@Override
259250
public void onComplete(CompletionContext<Object, ServiceInstance, Object> completionContext) {
251+
completeLog.clear();
260252
completeLog.put(getName() + UUID.randomUUID(), completionContext);
261253
}
262254

@@ -273,18 +265,13 @@ Map<String, Request<Object>> getStartRequestLog() {
273265
}
274266

275267
protected String getName() {
276-
return this.getClass().getSimpleName();
268+
return getClass().getSimpleName();
277269
}
278270

279271
}
280272

281273
protected static class AnotherLoadBalancerLifecycle extends TestLoadBalancerLifecycle {
282274

283-
@Override
284-
protected String getName() {
285-
return this.getClass().getSimpleName();
286-
}
287-
288275
}
289276

290277
}

0 commit comments

Comments
 (0)