Skip to content

Commit 12acc97

Browse files
authored
add some basic tests (#1559)
* add some basic tests Signed-off-by: wind57 <eugen.rabii@gmail.com> * drop sout statement Signed-off-by: wind57 <eugen.rabii@gmail.com> * fix failing tests Signed-off-by: wind57 <eugen.rabii@gmail.com> * correct doc Signed-off-by: wind57 <eugen.rabii@gmail.com> * empty Signed-off-by: wind57 <eugen.rabii@gmail.com> --------- Signed-off-by: wind57 <eugen.rabii@gmail.com>
1 parent fb3e1d8 commit 12acc97

File tree

2 files changed

+152
-13
lines changed

2 files changed

+152
-13
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/*
2+
* Copyright 2012-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.loadbalancer.cache;
18+
19+
import java.time.Duration;
20+
import java.util.List;
21+
import java.util.concurrent.atomic.AtomicInteger;
22+
23+
import org.junit.jupiter.api.AfterEach;
24+
import org.junit.jupiter.api.Test;
25+
import reactor.core.publisher.Flux;
26+
27+
import org.springframework.cloud.client.DefaultServiceInstance;
28+
import org.springframework.cloud.client.ServiceInstance;
29+
import org.springframework.cloud.loadbalancer.core.CachingServiceInstanceListSupplier;
30+
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
31+
32+
import static org.assertj.core.api.Assertions.assertThat;
33+
import static org.springframework.cloud.loadbalancer.core.CachingServiceInstanceListSupplier.SERVICE_INSTANCE_CACHE_NAME;
34+
35+
/**
36+
* @author wind57
37+
*/
38+
class CaffeineBasedLoadBalancerCacheManagerTests {
39+
40+
private static final String SERVICE_ID = "mock-service-id";
41+
42+
private final CaffeineBasedLoadBalancerCacheManager caffeineBasedLoadBalancerCacheManager = new CaffeineBasedLoadBalancerCacheManager(
43+
SERVICE_INSTANCE_CACHE_NAME, getLoadBalancerCacheProperties());
44+
45+
/**
46+
* <pre>
47+
* - cache has a TTL of 3 seconds
48+
* - we issue a GET and its not in the cache (counter is incremented)
49+
* - we issue a second GET and it's in the cache this time (counter stays the same)
50+
* </pre>
51+
*/
52+
@Test
53+
void testSecondGetRetrievedFromCache() {
54+
55+
ServiceInstanceListSupplier serviceInstanceListSupplier = new StubServiceInstanceListSupplier();
56+
57+
CachingServiceInstanceListSupplier cachingServiceInstanceListSupplier = new CachingServiceInstanceListSupplier(
58+
serviceInstanceListSupplier, caffeineBasedLoadBalancerCacheManager);
59+
60+
List<ServiceInstance> serviceInstances = cachingServiceInstanceListSupplier.get().blockFirst();
61+
assertThat(serviceInstances).hasSize(1);
62+
// the first time we retrieve, the entry is not in the cache
63+
assertThat(StubServiceInstanceListSupplier.counter.get()).isEqualTo(1);
64+
65+
List<ServiceInstance> serviceInstancesInTheCache = cachingServiceInstanceListSupplier.get().blockFirst();
66+
assertThat(serviceInstancesInTheCache).hasSize(1);
67+
// the second time we retrieve, the entry is in the cache
68+
// the underlying list supplier is not called
69+
assertThat(StubServiceInstanceListSupplier.counter.get()).isEqualTo(1);
70+
71+
}
72+
73+
/**
74+
* <pre>
75+
* - cache has a TTL of 3 seconds
76+
* - we issue a GET and its not in the cache (counter is incremented)
77+
* - we issue a second GET and it's in the cache this time (counter stays the same)
78+
* - we wait for 4 seconds (entry in the cache is evicted)
79+
* - we issue one more GET and this time its not in the cache (counter is incremented to 2)
80+
* </pre>
81+
*/
82+
@Test
83+
void testSecondGetNoInTheCache() throws Exception {
84+
85+
ServiceInstanceListSupplier serviceInstanceListSupplier = new StubServiceInstanceListSupplier();
86+
87+
CachingServiceInstanceListSupplier cachingServiceInstanceListSupplier = new CachingServiceInstanceListSupplier(
88+
serviceInstanceListSupplier, caffeineBasedLoadBalancerCacheManager);
89+
90+
List<ServiceInstance> serviceInstances = cachingServiceInstanceListSupplier.get().blockFirst();
91+
assertThat(serviceInstances).hasSize(1);
92+
// the first time we retrieve, the entry is not in the cache
93+
assertThat(StubServiceInstanceListSupplier.counter.get()).isEqualTo(1);
94+
95+
List<ServiceInstance> serviceInstancesInTheCache = cachingServiceInstanceListSupplier.get().blockFirst();
96+
assertThat(serviceInstancesInTheCache).hasSize(1);
97+
// the second time we retrieve, the entry is in the cache,
98+
// the underlying list supplier is not called
99+
assertThat(StubServiceInstanceListSupplier.counter.get()).isEqualTo(1);
100+
101+
Thread.sleep(4_000);
102+
103+
List<ServiceInstance> serviceInstancesNotInTheCache = cachingServiceInstanceListSupplier.get().blockFirst();
104+
assertThat(serviceInstancesNotInTheCache).hasSize(1);
105+
// the third time we retrieve, the entry is not in the cache,
106+
// the underlying list supplier is called
107+
assertThat(StubServiceInstanceListSupplier.counter.get()).isEqualTo(2);
108+
109+
}
110+
111+
@AfterEach
112+
void afterEach() {
113+
StubServiceInstanceListSupplier.counter.set(0);
114+
}
115+
116+
private static LoadBalancerCacheProperties getLoadBalancerCacheProperties() {
117+
LoadBalancerCacheProperties properties = new LoadBalancerCacheProperties();
118+
properties.setCapacity(100);
119+
properties.setTtl(Duration.ofSeconds(3));
120+
return properties;
121+
}
122+
123+
static class StubServiceInstanceListSupplier implements ServiceInstanceListSupplier {
124+
125+
static AtomicInteger counter = new AtomicInteger(0);
126+
127+
@Override
128+
public String getServiceId() {
129+
return SERVICE_ID;
130+
}
131+
132+
@Override
133+
public Flux<List<ServiceInstance>> get() {
134+
List<ServiceInstance> serviceInstances = List
135+
.of(new DefaultServiceInstance(SERVICE_ID, SERVICE_ID, "localhost", 80, false));
136+
return Flux.just(serviceInstances).doOnNext(x -> {
137+
counter.incrementAndGet();
138+
});
139+
}
140+
141+
}
142+
143+
}

spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/CachingServiceInstanceListSupplierTests.java

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,14 @@
4848
*
4949
* @author Olga Maciaszek-Sharma
5050
*/
51-
@SpringBootTest(classes = CachingServiceInstanceListSupplierTests.TestConfig.class)
51+
@SpringBootTest(classes = CachingServiceInstanceListSupplierTests.TestConfig.class,
52+
properties = { "loadbalancer.client.name=test" })
5253
class CachingServiceInstanceListSupplierTests {
5354

54-
public static final String SERVICE_ID = "test";
55-
56-
static {
57-
System.setProperty("loadbalancer.client.name", SERVICE_ID);
58-
}
55+
private static final String SERVICE_ID = "test";
5956

6057
@Autowired
61-
BlockingLoadBalancerClient blockingLoadBalancerClient;
58+
private BlockingLoadBalancerClient blockingLoadBalancerClient;
6259

6360
private static DefaultServiceInstance instance(String host, boolean secure) {
6461
return new DefaultServiceInstance(SERVICE_ID, SERVICE_ID, host, 80, secure);
@@ -74,10 +71,10 @@ void shouldNotHangOnCachingWhenDelegateReturnsInfiniteStream() {
7471

7572
@Configuration(proxyBeanMethods = false)
7673
@Import(LoadBalancerCacheAutoConfiguration.class)
77-
protected static class TestConfig {
74+
static class TestConfig {
7875

7976
@Bean
80-
public ReactiveDiscoveryClient reactiveDiscoveryClient() {
77+
ReactiveDiscoveryClient reactiveDiscoveryClient() {
8178
return new ReactiveDiscoveryClient() {
8279
@Override
8380
public String description() {
@@ -107,18 +104,17 @@ LoadBalancerClientFactory loadBalancerClientFactory(LoadBalancerClientsPropertie
107104
}
108105

109106
@Bean
110-
BlockingLoadBalancerClient blockingLoadBalancerClient(LoadBalancerClientFactory loadBalancerClientFactory,
111-
LoadBalancerProperties properties) {
107+
BlockingLoadBalancerClient blockingLoadBalancerClient(LoadBalancerClientFactory loadBalancerClientFactory) {
112108
return new BlockingLoadBalancerClient(loadBalancerClientFactory);
113109
}
114110

115111
@Bean
116-
public LoadBalancerClientsProperties loadBalancerClientsProperties() {
112+
LoadBalancerClientsProperties loadBalancerClientsProperties() {
117113
return new LoadBalancerClientsProperties();
118114
}
119115

120116
@Bean
121-
public WebClient.Builder webClientBuilder() {
117+
WebClient.Builder webClientBuilder() {
122118
return WebClient.builder();
123119
}
124120

0 commit comments

Comments
 (0)