CaffeineBasedLoadBalancerCacheManagerTests.java
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.loadbalancer.cache;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Flux;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.CachingServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.cloud.loadbalancer.core.CachingServiceInstanceListSupplier.SERVICE_INSTANCE_CACHE_NAME;
/**
* @author wind57
*/
class CaffeineBasedLoadBalancerCacheManagerTests {
private static final String SERVICE_ID = "mock-service-id";
private final CaffeineBasedLoadBalancerCacheManager caffeineBasedLoadBalancerCacheManager = new CaffeineBasedLoadBalancerCacheManager(
SERVICE_INSTANCE_CACHE_NAME, getLoadBalancerCacheProperties());
/**
* <pre>
* - cache has a TTL of 3 seconds
* - we issue a GET and its not in the cache (counter is incremented)
* - we issue a second GET and it's in the cache this time (counter stays the same)
* </pre>
*/
@Test
void testSecondGetRetrievedFromCache() {
ServiceInstanceListSupplier serviceInstanceListSupplier = new StubServiceInstanceListSupplier();
CachingServiceInstanceListSupplier cachingServiceInstanceListSupplier = new CachingServiceInstanceListSupplier(
serviceInstanceListSupplier, caffeineBasedLoadBalancerCacheManager);
List<ServiceInstance> serviceInstances = cachingServiceInstanceListSupplier.get().blockFirst();
assertThat(serviceInstances).hasSize(1);
// the first time we retrieve, the entry is not in the cache
assertThat(StubServiceInstanceListSupplier.counter.get()).isEqualTo(1);
List<ServiceInstance> serviceInstancesInTheCache = cachingServiceInstanceListSupplier.get().blockFirst();
assertThat(serviceInstancesInTheCache).hasSize(1);
// the second time we retrieve, the entry is in the cache
// the underlying list supplier is not called
assertThat(StubServiceInstanceListSupplier.counter.get()).isEqualTo(1);
}
/**
* <pre>
* - cache has a TTL of 3 seconds
* - we issue a GET and its not in the cache (counter is incremented)
* - we issue a second GET and it's in the cache this time (counter stays the same)
* - we wait for 4 seconds (entry in the cache is evicted)
* - we issue one more GET and this time its not in the cache (counter is incremented to 2)
* </pre>
*/
@Test
void testSecondGetNoInTheCache() throws Exception {
ServiceInstanceListSupplier serviceInstanceListSupplier = new StubServiceInstanceListSupplier();
CachingServiceInstanceListSupplier cachingServiceInstanceListSupplier = new CachingServiceInstanceListSupplier(
serviceInstanceListSupplier, caffeineBasedLoadBalancerCacheManager);
List<ServiceInstance> serviceInstances = cachingServiceInstanceListSupplier.get().blockFirst();
assertThat(serviceInstances).hasSize(1);
// the first time we retrieve, the entry is not in the cache
assertThat(StubServiceInstanceListSupplier.counter.get()).isEqualTo(1);
List<ServiceInstance> serviceInstancesInTheCache = cachingServiceInstanceListSupplier.get().blockFirst();
assertThat(serviceInstancesInTheCache).hasSize(1);
// the second time we retrieve, the entry is in the cache,
// the underlying list supplier is not called
assertThat(StubServiceInstanceListSupplier.counter.get()).isEqualTo(1);
Thread.sleep(4_000);
List<ServiceInstance> serviceInstancesNotInTheCache = cachingServiceInstanceListSupplier.get().blockFirst();
assertThat(serviceInstancesNotInTheCache).hasSize(1);
// the third time we retrieve, the entry is not in the cache,
// the underlying list supplier is called
assertThat(StubServiceInstanceListSupplier.counter.get()).isEqualTo(2);
}
@AfterEach
void afterEach() {
StubServiceInstanceListSupplier.counter.set(0);
}
private static LoadBalancerCacheProperties getLoadBalancerCacheProperties() {
LoadBalancerCacheProperties properties = new LoadBalancerCacheProperties();
properties.setCapacity(100);
properties.setTtl(Duration.ofSeconds(3));
return properties;
}
static class StubServiceInstanceListSupplier implements ServiceInstanceListSupplier {
static AtomicInteger counter = new AtomicInteger(0);
@Override
public String getServiceId() {
return SERVICE_ID;
}
@Override
public Flux<List<ServiceInstance>> get() {
List<ServiceInstance> serviceInstances = List
.of(new DefaultServiceInstance(SERVICE_ID, SERVICE_ID, "localhost", 80, false));
return Flux.just(serviceInstances).doOnNext(x -> {
counter.incrementAndGet();
});
}
}
}