Skip to content

Commit e046840

Browse files
committed
Merge remote-tracking branch 'origin/4.1.x' into 4.2.x
2 parents 45bbe08 + 383d067 commit e046840

File tree

3 files changed

+188
-346
lines changed

3 files changed

+188
-346
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.
@@ -27,16 +27,13 @@
2727
import org.junit.jupiter.api.BeforeEach;
2828
import org.junit.jupiter.api.Disabled;
2929
import org.junit.jupiter.api.Test;
30+
import reactor.core.publisher.Mono;
3031

3132
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;
3533
import org.springframework.boot.test.web.server.LocalServerPort;
3634
import org.springframework.cloud.client.DefaultServiceInstance;
3735
import org.springframework.cloud.client.ServiceInstance;
3836
import org.springframework.cloud.client.discovery.DiscoveryClient;
39-
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
4037
import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryProperties;
4138
import org.springframework.cloud.client.loadbalancer.CompletionContext;
4239
import org.springframework.cloud.client.loadbalancer.DefaultRequestContext;
@@ -45,93 +42,98 @@
4542
import org.springframework.cloud.client.loadbalancer.Request;
4643
import org.springframework.cloud.client.loadbalancer.Response;
4744
import org.springframework.cloud.client.loadbalancer.ResponseData;
48-
import org.springframework.context.annotation.Bean;
45+
import org.springframework.http.HttpMethod;
4946
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;
47+
import org.springframework.http.ResponseEntity;
5348
import org.springframework.web.reactive.function.client.WebClient;
5449

5550
import static org.assertj.core.api.Assertions.assertThat;
56-
import static org.assertj.core.api.Assertions.assertThatCode;
51+
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
52+
import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode;
5753
import static org.assertj.core.api.BDDAssertions.then;
58-
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
5954

6055
/**
61-
* Tests for {@link ReactorLoadBalancerExchangeFilterFunction}.
56+
* Base class for {@link LoadBalancedExchangeFilterFunction} integration tests.
6257
*
6358
* @author Olga Maciaszek-Sharma
64-
* @author Charu Covindane
6559
*/
66-
@SuppressWarnings("ConstantConditions")
67-
@SpringBootTest(webEnvironment = RANDOM_PORT)
68-
class ReactorLoadBalancerExchangeFilterFunctionTests {
60+
@SuppressWarnings("DataFlowIssue")
61+
abstract class AbstractLoadBalancerExchangeFilterFunctionIntegrationTests {
6962

7063
@Autowired
71-
private ReactorLoadBalancerExchangeFilterFunction loadBalancerFunction;
64+
protected LoadBalancedExchangeFilterFunction loadBalancerFunction;
7265

7366
@Autowired
74-
private SimpleDiscoveryProperties properties;
67+
protected SimpleDiscoveryProperties properties;
7568

7669
@Autowired
77-
private LoadBalancerProperties loadBalancerProperties;
70+
protected LoadBalancerProperties loadBalancerProperties;
7871

7972
@Autowired
80-
private ReactiveLoadBalancer.Factory<ServiceInstance> factory;
73+
protected ReactiveLoadBalancer.Factory<ServiceInstance> factory;
8174

8275
@LocalServerPort
83-
private int port;
76+
protected int port;
8477

8578
@BeforeEach
86-
void setUp() {
79+
protected void setUp() {
8780
DefaultServiceInstance instance = new DefaultServiceInstance();
8881
instance.setServiceId("testservice");
89-
instance.setUri(URI.create("http://localhost:" + this.port));
82+
instance.setUri(URI.create("http://localhost:" + port));
9083
DefaultServiceInstance instanceWithNoLifecycleProcessors = new DefaultServiceInstance();
9184
instanceWithNoLifecycleProcessors.setServiceId("serviceWithNoLifecycleProcessors");
92-
instanceWithNoLifecycleProcessors.setUri(URI.create("http://localhost:" + this.port));
85+
instanceWithNoLifecycleProcessors.setUri(URI.create("http://localhost:" + port));
9386
properties.getInstances().put("testservice", Collections.singletonList(instance));
9487
properties.getInstances()
9588
.put("serviceWithNoLifecycleProcessors", Collections.singletonList(instanceWithNoLifecycleProcessors));
9689
}
9790

9891
@Test
9992
void correctResponseReturnedForExistingHostAndInstancePresent() {
100-
ClientResponse clientResponse = WebClient.builder()
93+
ResponseEntity<String> response = WebClient.builder()
10194
.baseUrl("http://testservice")
10295
.filter(loadBalancerFunction)
10396
.build()
10497
.get()
10598
.uri("/hello")
106-
.exchange()
99+
.retrieve()
100+
.toEntity(String.class)
107101
.block();
108-
then(clientResponse.statusCode()).isEqualTo(HttpStatus.OK);
109-
then(clientResponse.bodyToMono(String.class).block()).isEqualTo("Hello World");
102+
then(response.getStatusCode()).isEqualTo(HttpStatus.OK);
103+
then(response.getBody()).isEqualTo("Hello World");
110104
}
111105

112106
@Test
113107
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);
108+
assertThatIllegalStateException()
109+
.isThrownBy(() -> WebClient.builder()
110+
.baseUrl("http://xxx")
111+
.filter(loadBalancerFunction)
112+
.defaultStatusHandler(httpStatusCode -> httpStatusCode.equals(HttpStatus.SERVICE_UNAVAILABLE),
113+
clientResponse -> Mono.just(new IllegalStateException("503")))
114+
.build()
115+
.get()
116+
.retrieve()
117+
.toBodilessEntity()
118+
.block())
119+
.withMessage("503");
122120
}
123121

124122
@Test
125123
@Disabled // FIXME 3.0.0
126124
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);
125+
assertThatIllegalStateException()
126+
.isThrownBy(() -> WebClient.builder()
127+
.baseUrl("http:///xxx")
128+
.filter(loadBalancerFunction)
129+
.defaultStatusHandler(httpStatusCode -> httpStatusCode.equals(HttpStatus.BAD_REQUEST),
130+
response -> Mono.just(new IllegalStateException("400")))
131+
.build()
132+
.get()
133+
.retrieve()
134+
.toBodilessEntity()
135+
.block())
136+
.withMessage("400");
135137
}
136138

137139
@Test
@@ -142,97 +144,88 @@ void exceptionNotThrownWhenFactoryReturnsNullLifecycleProcessorsMap() {
142144
.build()
143145
.get()
144146
.uri("/hello")
145-
.exchange()
147+
.exchangeToMono(clientResponse -> clientResponse.bodyToMono(String.class))
146148
.block()).doesNotThrowAnyException();
147149
}
148150

149151
@Test
150152
void loadBalancerLifecycleCallbacksExecuted() {
151153
final String callbackTestHint = "callbackTestHint";
152154
loadBalancerProperties.getHint().put("testservice", "callbackTestHint");
153-
ClientResponse clientResponse = WebClient.builder()
155+
156+
ResponseEntity<Void> response = WebClient.builder()
154157
.baseUrl("http://testservice")
155158
.filter(loadBalancerFunction)
156159
.build()
157160
.get()
158161
.uri("/callback")
159-
.exchange()
162+
.retrieve()
163+
.toBodilessEntity()
160164
.block();
161165

162166
Collection<Request<Object>> lifecycleLogRequests = ((TestLoadBalancerLifecycle) factory
163167
.getInstances("testservice", LoadBalancerLifecycle.class)
164168
.get("loadBalancerLifecycle")).getStartLog().values();
165-
Collection<Request<Object>> lifecycleStartedLogRequests = ((TestLoadBalancerLifecycle) factory
169+
Collection<Request<Object>> lifecycleLogStartRequests = ((TestLoadBalancerLifecycle) factory
166170
.getInstances("testservice", LoadBalancerLifecycle.class)
167171
.get("loadBalancerLifecycle")).getStartRequestLog().values();
168172
Collection<CompletionContext<Object, ServiceInstance, Object>> anotherLifecycleLogRequests = ((AnotherLoadBalancerLifecycle) factory
169173
.getInstances("testservice", LoadBalancerLifecycle.class)
170174
.get("anotherLoadBalancerLifecycle")).getCompleteLog().values();
171-
then(clientResponse.statusCode()).isEqualTo(HttpStatus.OK);
175+
then(response.getStatusCode()).isEqualTo(HttpStatus.OK);
172176
assertThat(lifecycleLogRequests).extracting(request -> ((DefaultRequestContext) request.getContext()).getHint())
173177
.contains(callbackTestHint);
174-
assertThat(lifecycleStartedLogRequests)
178+
assertThat(lifecycleLogStartRequests)
175179
.extracting(request -> ((DefaultRequestContext) request.getContext()).getHint())
176180
.contains(callbackTestHint);
177181
assertThat(anotherLifecycleLogRequests)
178182
.extracting(completionContext -> ((ResponseData) completionContext.getClientResponse()).getRequestData()
179-
.getUrl()
180-
.toString())
181-
.contains("http://testservice/callback");
183+
.getHttpMethod())
184+
.contains(HttpMethod.GET);
182185
}
183186

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

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

196-
@GetMapping("/callback")
197-
String callbackTestResult() {
198-
return "callbackTestResult";
204+
@Override
205+
public ReactiveLoadBalancer<ServiceInstance> getInstance(String serviceId) {
206+
return new DiscoveryClientBasedReactiveLoadBalancer(serviceId, discoveryClient);
199207
}
200208

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-
};
209+
@SuppressWarnings({ "rawtypes", "unchecked" })
210+
@Override
211+
public <X> Map<String, X> getInstances(String name, Class<X> type) {
212+
if (name.equals("serviceWithNoLifecycleProcessors")) {
213+
return null;
214+
}
215+
Map lifecycleProcessors = new HashMap<>();
216+
lifecycleProcessors.put("loadBalancerLifecycle", testLoadBalancerLifecycle);
217+
lifecycleProcessors.put("anotherLoadBalancerLifecycle", anotherLoadBalancerLifecycle);
218+
return lifecycleProcessors;
219+
}
220+
221+
@Override
222+
public <X> X getInstance(String name, Class<?> clazz, Class<?>... generics) {
223+
return null;
224+
}
225+
226+
@Override
227+
public LoadBalancerProperties getProperties(String serviceId) {
228+
return properties;
236229
}
237230

238231
}
@@ -257,6 +250,7 @@ public void onStartRequest(Request<Object> request, Response<ServiceInstance> lb
257250

258251
@Override
259252
public void onComplete(CompletionContext<Object, ServiceInstance, Object> completionContext) {
253+
completeLog.clear();
260254
completeLog.put(getName() + UUID.randomUUID(), completionContext);
261255
}
262256

@@ -273,18 +267,13 @@ Map<String, Request<Object>> getStartRequestLog() {
273267
}
274268

275269
protected String getName() {
276-
return this.getClass().getSimpleName();
270+
return getClass().getSimpleName();
277271
}
278272

279273
}
280274

281275
protected static class AnotherLoadBalancerLifecycle extends TestLoadBalancerLifecycle {
282276

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

290279
}

0 commit comments

Comments
 (0)