diff --git a/bucket4j-spring-boot-starter/pom.xml b/bucket4j-spring-boot-starter/pom.xml
index c05deb23..1060a462 100644
--- a/bucket4j-spring-boot-starter/pom.xml
+++ b/bucket4j-spring-boot-starter/pom.xml
@@ -17,7 +17,7 @@
UTF-8
UTF-8
17
- 3.23.5
+ 3.24.3
2.15.0
diff --git a/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/filter/Bucket4JBaseConfiguration.java b/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/filter/Bucket4JBaseConfiguration.java
index 8282be33..357fe535 100644
--- a/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/filter/Bucket4JBaseConfiguration.java
+++ b/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/filter/Bucket4JBaseConfiguration.java
@@ -29,7 +29,6 @@
import io.github.bucket4j.Bandwidth;
import io.github.bucket4j.BucketConfiguration;
import io.github.bucket4j.ConfigurationBuilder;
-import io.github.bucket4j.Refill;
import lombok.extern.slf4j.Slf4j;
/**
@@ -138,14 +137,14 @@ private ConfigurationBuilder prepareBucket4jConfigurationBuilder(RateLimit rl) {
long refillCapacity = bandWidth.getRefillCapacity() != null ? bandWidth.getRefillCapacity() : bandWidth.getCapacity();
var refillPeriod = Duration.of(bandWidth.getTime(), bandWidth.getUnit());
var bucket4jBandWidth = switch(bandWidth.getRefillSpeed()) {
- case GREEDY -> Bandwidth.classic(capacity, Refill.greedy(refillCapacity, refillPeriod)).withId(bandWidth.getId());
- case INTERVAL -> Bandwidth.classic(capacity, Refill.intervally(refillCapacity, refillPeriod)).withId(bandWidth.getId());
- default -> throw new IllegalStateException("Unsupported Refill type: " + bandWidth.getRefillSpeed());
- };
+ case GREEDY -> Bandwidth.builder().capacity(capacity).refillGreedy(refillCapacity, refillPeriod).id(bandWidth.getId());
+ case INTERVAL -> Bandwidth.builder().capacity(capacity).refillIntervally(refillCapacity, refillPeriod).id(bandWidth.getId());
+ };
+
if(bandWidth.getInitialCapacity() != null) {
- bucket4jBandWidth = bucket4jBandWidth.withInitialTokens(bandWidth.getInitialCapacity());
+ bucket4jBandWidth = bucket4jBandWidth.initialTokens(bandWidth.getInitialCapacity());
}
- configBuilder = configBuilder.addLimit(bucket4jBandWidth);
+ configBuilder = configBuilder.addLimit(bucket4jBandWidth.build());
}
return configBuilder;
}
diff --git a/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/filter/reactive/AbstractReactiveFilter.java b/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/filter/reactive/AbstractReactiveFilter.java
index 336560c1..a85e2d0d 100644
--- a/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/filter/reactive/AbstractReactiveFilter.java
+++ b/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/filter/reactive/AbstractReactiveFilter.java
@@ -2,9 +2,11 @@
import static java.nio.charset.StandardCharsets.UTF_8;
+import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
+import com.giffing.bucket4j.spring.boot.starter.context.ConsumptionProbeHolder;
+import com.giffing.bucket4j.spring.boot.starter.context.RateLimitCheck;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
@@ -22,9 +24,9 @@
@Data
@Slf4j
public class AbstractReactiveFilter {
-
+
private FilterConfiguration filterConfig;
-
+
public AbstractReactiveFilter(FilterConfiguration filterConfig) {
this.filterConfig = filterConfig;
}
@@ -36,37 +38,28 @@ public void setFilterConfig(FilterConfiguration filterConfig)
protected boolean urlMatches(ServerHttpRequest request) {
return request.getURI().getPath().matches(filterConfig.getUrl());
}
-
+
protected Mono chainWithRateLimitCheck(ServerWebExchange exchange, ReactiveFilterChain chain) {
log.debug("reate-limit-check;method:{};uri:{}", exchange.getRequest().getMethod(), exchange.getRequest().getURI());
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
- List> asyncConsumptionProbes = filterConfig.getRateLimitChecks()
- .stream()
- .map(rl -> rl.rateLimit(request))
- .filter(cph -> cph != null && cph.getConsumptionProbeCompletableFuture() != null)
- .map(cph -> Mono.fromFuture(cph.getConsumptionProbeCompletableFuture()))
- .toList();
+ List> asyncConsumptionProbes = new ArrayList<>();
+ for (RateLimitCheck rlc : filterConfig.getRateLimitChecks()) {
+ ConsumptionProbeHolder cph = rlc.rateLimit(request);
+ if(cph != null && cph.getConsumptionProbeCompletableFuture() != null){
+ asyncConsumptionProbes.add(Mono.fromFuture(cph.getConsumptionProbeCompletableFuture()));
+ if(filterConfig.getStrategy() == RateLimitConditionMatchingStrategy.FIRST){
+ break;
+ }
+ }
+ }
if(asyncConsumptionProbes.isEmpty()) {
return chain.apply(exchange);
}
- AtomicInteger consumptionProbeCounter = new AtomicInteger(0);
return Flux
- .concat(asyncConsumptionProbes)
- //.takeWhile(Objects::nonNull)
- .doOnNext(cp -> consumptionProbeCounter.incrementAndGet())
- .takeWhile(cp -> shouldTakeMoreConsumptionProbe(consumptionProbeCounter))
- .reduce(this::reduceConsumptionProbe)
- .flatMap(consumptionProbe -> handleConsumptionProbe(exchange, chain, response, consumptionProbe));
-
- }
-
- protected boolean shouldTakeMoreConsumptionProbe(AtomicInteger consumptionProbeCounter) {
- boolean shouldTakeMore = filterConfig.getStrategy().equals(RateLimitConditionMatchingStrategy.ALL)
- ||
- (filterConfig.getStrategy().equals(RateLimitConditionMatchingStrategy.FIRST) && consumptionProbeCounter.get() == 1);
- log.debug("take-more-probes:{};probe-index:{};matching-strategy:{}", shouldTakeMore, consumptionProbeCounter.get(), filterConfig.getStrategy());
- return shouldTakeMore;
+ .concat(asyncConsumptionProbes)
+ .reduce(this::reduceConsumptionProbe)
+ .flatMap(consumptionProbe -> handleConsumptionProbe(exchange, chain, response, consumptionProbe));
}
protected ConsumptionProbe reduceConsumptionProbe(ConsumptionProbe x, ConsumptionProbe y) {
@@ -76,7 +69,7 @@ protected ConsumptionProbe reduceConsumptionProbe(ConsumptionProbe x, Consumptio
} else if(!y.isConsumed()) {
result = y;
} else {
- result = x.getRemainingTokens() < y.getRemainingTokens() ? x : y;
+ result = x.getRemainingTokens() < y.getRemainingTokens() ? x : y;
}
log.debug("reduce-probes;result-isConsumed:{};result-getremainingTokens:{};x-isConsumed:{};x-getremainingTokens{};y-isConsumed:{};y-getremainingTokens{}",
result.isConsumed(), result.getRemainingTokens(),
@@ -84,15 +77,15 @@ protected ConsumptionProbe reduceConsumptionProbe(ConsumptionProbe x, Consumptio
y.isConsumed(), y.getRemainingTokens());
return result;
}
-
+
protected Mono handleConsumptionProbe(ServerWebExchange exchange, ReactiveFilterChain chain,
ServerHttpResponse response, ConsumptionProbe cp) {
- log.debug("probe-results;isConsumed:{};remainingTokens:{};nanosToWaitForRefill:{};nanosToWaitForReset:{}",
- cp.isConsumed(),
- cp.getRemainingTokens(),
- cp.getNanosToWaitForRefill(),
+ log.debug("probe-results;isConsumed:{};remainingTokens:{};nanosToWaitForRefill:{};nanosToWaitForReset:{}",
+ cp.isConsumed(),
+ cp.getRemainingTokens(),
+ cp.getNanosToWaitForRefill(),
cp.getNanosToWaitForReset());
-
+
if(!cp.isConsumed()) {
if(Boolean.FALSE.equals(filterConfig.getHideHttpResponseHeaders())) {
filterConfig.getHttpResponseHeaders().forEach(response.getHeaders()::addIfAbsent);
@@ -101,7 +94,7 @@ protected Mono handleConsumptionProbe(ServerWebExchange exchange, Reactive
response.setStatusCode(filterConfig.getHttpStatusCode());
response.getHeaders().set("Content-Type", filterConfig.getHttpContentType());
DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(filterConfig.getHttpResponseBody().getBytes(UTF_8));
- return response.writeWith(Flux.just(buffer));
+ return response.writeWith(Flux.just(buffer));
} else {
return Mono.error(new ReactiveRateLimitException("HTTP ResponseBody is null"));
}
@@ -112,6 +105,4 @@ protected Mono handleConsumptionProbe(ServerWebExchange exchange, Reactive
}
return chain.apply(exchange);
}
-
-
}
diff --git a/bucket4j-spring-boot-starter/src/test/java/com/giffing/bucket4j/spring/boot/starter/gateway/SpringCloudGatewayRateLimitFilterTest.java b/bucket4j-spring-boot-starter/src/test/java/com/giffing/bucket4j/spring/boot/starter/gateway/SpringCloudGatewayRateLimitFilterTest.java
index 8b0f31f7..2f9fbebb 100644
--- a/bucket4j-spring-boot-starter/src/test/java/com/giffing/bucket4j/spring/boot/starter/gateway/SpringCloudGatewayRateLimitFilterTest.java
+++ b/bucket4j-spring-boot-starter/src/test/java/com/giffing/bucket4j/spring/boot/starter/gateway/SpringCloudGatewayRateLimitFilterTest.java
@@ -39,52 +39,52 @@
class SpringCloudGatewayRateLimitFilterTest {
private GlobalFilter filter;
- private FilterConfiguration configuration;
- private RateLimitCheck rateLimitCheck1;
- private RateLimitCheck rateLimitCheck2;
- private RateLimitCheck rateLimitCheck3;
+ private FilterConfiguration configuration;
+ private RateLimitCheck rateLimitCheck1;
+ private RateLimitCheck rateLimitCheck2;
+ private RateLimitCheck rateLimitCheck3;
private ServerWebExchange exchange;
private GatewayFilterChain chain;
-
-
+
+
private ServerHttpResponse serverHttpResponse;
-
+
@BeforeEach
- public void setup() throws URISyntaxException {
- rateLimitCheck1 = mock(RateLimitCheck.class);
- rateLimitCheck2 = mock(RateLimitCheck.class);
- rateLimitCheck3 = mock(RateLimitCheck.class);
-
- exchange = Mockito.mock(ServerWebExchange.class);
-
- ServerHttpRequest serverHttpRequest = Mockito.mock(ServerHttpRequest.class);
- URI uri = new URI("url");
- when(serverHttpRequest.getURI()).thenReturn(uri);
+ public void setup() throws URISyntaxException {
+ rateLimitCheck1 = mock(RateLimitCheck.class);
+ rateLimitCheck2 = mock(RateLimitCheck.class);
+ rateLimitCheck3 = mock(RateLimitCheck.class);
+
+ exchange = Mockito.mock(ServerWebExchange.class);
+
+ ServerHttpRequest serverHttpRequest = Mockito.mock(ServerHttpRequest.class);
+ URI uri = new URI("url");
+ when(serverHttpRequest.getURI()).thenReturn(uri);
when(exchange.getRequest()).thenReturn(serverHttpRequest);
-
+
serverHttpResponse = Mockito.mock(ServerHttpResponse.class);
- when(exchange.getResponse()).thenReturn(serverHttpResponse);
-
+ when(exchange.getResponse()).thenReturn(serverHttpResponse);
+
chain = Mockito.mock(GatewayFilterChain.class);
when(chain.filter(exchange)).thenReturn(Mono.empty());
-
- configuration = new FilterConfiguration();
- configuration.setRateLimitChecks(Arrays.asList(rateLimitCheck1, rateLimitCheck2, rateLimitCheck3));
- configuration.setUrl(".*");
- filter = new SpringCloudGatewayRateLimitFilter(configuration);
- }
-
- @Test
+
+ configuration = new FilterConfiguration<>();
+ configuration.setRateLimitChecks(Arrays.asList(rateLimitCheck1, rateLimitCheck2, rateLimitCheck3));
+ configuration.setUrl(".*");
+ filter = new SpringCloudGatewayRateLimitFilter(configuration);
+ }
+
+ @Test
void should_throw_rate_limit_exception_with_no_remaining_tokens() {
-
+
configuration.setStrategy(RateLimitConditionMatchingStrategy.FIRST);
- rateLimitConfig(0L, rateLimitCheck1);
- HttpHeaders httpHeaders = Mockito.mock(HttpHeaders.class);
- when(serverHttpResponse.getHeaders()).thenReturn(httpHeaders);
-
- AtomicBoolean hasRateLimitError = new AtomicBoolean(false);
+ rateLimitConfig(0L, rateLimitCheck1);
+ HttpHeaders httpHeaders = Mockito.mock(HttpHeaders.class);
+ when(serverHttpResponse.getHeaders()).thenReturn(httpHeaders);
+
+ AtomicBoolean hasRateLimitError = new AtomicBoolean(false);
Mono result = filter.filter(exchange, chain)
.onErrorResume(ReactiveRateLimitException.class, (e) -> {
hasRateLimitError.set(true);
@@ -93,63 +93,62 @@ void should_throw_rate_limit_exception_with_no_remaining_tokens() {
result.subscribe();
Assertions.assertTrue(hasRateLimitError.get());
}
-
+
@Test
void should_execute_all_checks_when_using_RateLimitConditionMatchingStrategy_All() throws URISyntaxException {
-
- configuration.setStrategy(RateLimitConditionMatchingStrategy.ALL);
-
- rateLimitConfig(30L, rateLimitCheck1);
- rateLimitConfig(0L, rateLimitCheck2);
- rateLimitConfig(0L, rateLimitCheck3);
-
- HttpHeaders httpHeaders = Mockito.mock(HttpHeaders.class);
- when(serverHttpResponse.getHeaders()).thenReturn(httpHeaders);
- final ArgumentCaptor captor = ArgumentCaptor.forClass(String.class);
-
- Mono result = filter.filter(exchange, chain);
- assertThrows(ReactiveRateLimitException.class, () -> {
- result.block();
- });
-
+
+ configuration.setStrategy(RateLimitConditionMatchingStrategy.ALL);
+
+ rateLimitConfig(30L, rateLimitCheck1);
+ rateLimitConfig(0L, rateLimitCheck2);
+ rateLimitConfig(0L, rateLimitCheck3);
+
+ HttpHeaders httpHeaders = Mockito.mock(HttpHeaders.class);
+ when(serverHttpResponse.getHeaders()).thenReturn(httpHeaders);
+ final ArgumentCaptor captor = ArgumentCaptor.forClass(String.class);
+
+ Mono result = filter.filter(exchange, chain);
+ assertThrows(ReactiveRateLimitException.class, () -> {
+ result.block();
+ });
+
verify(rateLimitCheck1, times(1)).rateLimit(any());
- verify(rateLimitCheck2, times(1)).rateLimit(any());
- verify(rateLimitCheck3, times(1)).rateLimit(any());
+ verify(rateLimitCheck2, times(1)).rateLimit(any());
+ verify(rateLimitCheck3, times(1)).rateLimit(any());
}
@Test
void should_execute_only_one_check_when_using_RateLimitConditionMatchingStrategy_FIRST() {
- configuration.setStrategy(RateLimitConditionMatchingStrategy.FIRST);
-
- rateLimitConfig(30L, rateLimitCheck1);
- rateLimitConfig(0L, rateLimitCheck2);
- rateLimitConfig(10L, rateLimitCheck3);
-
- HttpHeaders httpHeaders = Mockito.mock(HttpHeaders.class);
- when(serverHttpResponse.getHeaders()).thenReturn(httpHeaders);
- final ArgumentCaptor captor = ArgumentCaptor.forClass(String.class);
-
+ configuration.setStrategy(RateLimitConditionMatchingStrategy.FIRST);
+
+ rateLimitConfig(30L, rateLimitCheck1);
+ rateLimitConfig(0L, rateLimitCheck2);
+ rateLimitConfig(10L, rateLimitCheck3);
+
+ HttpHeaders httpHeaders = Mockito.mock(HttpHeaders.class);
+ when(serverHttpResponse.getHeaders()).thenReturn(httpHeaders);
+ final ArgumentCaptor captor = ArgumentCaptor.forClass(String.class);
+
Mono result = filter.filter(exchange, chain);
result.block();
-
- verify(httpHeaders, times(1)).set(any(), captor.capture());
-
- List values = captor.getAllValues();
- Assertions.assertEquals("30", values.stream().findFirst().get());
-
- verify(rateLimitCheck1, times(1)).rateLimit(any());
- verify(rateLimitCheck2, times(1)).rateLimit(any());
- verify(rateLimitCheck3, times(1)).rateLimit(any());
+
+ verify(httpHeaders, times(1)).set(any(), captor.capture());
+
+ List values = captor.getAllValues();
+ Assertions.assertEquals("30", values.stream().findFirst().get());
+
+ verify(rateLimitCheck1, times(1)).rateLimit(any());
+ verify(rateLimitCheck2, times(0)).rateLimit(any());
+ verify(rateLimitCheck3, times(0)).rateLimit(any());
}
- private void rateLimitConfig(Long remainingTokens, RateLimitCheck rateLimitCheck) {
+ private void rateLimitConfig(Long remainingTokens, RateLimitCheck rateLimitCheck) {
ConsumptionProbeHolder consumptionHolder = Mockito.mock(ConsumptionProbeHolder.class);
- ConsumptionProbe probe = Mockito.mock(ConsumptionProbe.class);
- when(probe.isConsumed()).thenReturn(remainingTokens > 0 ? true : false);
+ ConsumptionProbe probe = Mockito.mock(ConsumptionProbe.class);
+ when(probe.isConsumed()).thenReturn(remainingTokens > 0);
when(probe.getRemainingTokens()).thenReturn(remainingTokens);
when(consumptionHolder.getConsumptionProbeCompletableFuture())
- .thenReturn(CompletableFuture.completedFuture(probe));
- when(rateLimitCheck.rateLimit(any())).thenReturn(consumptionHolder);
+ .thenReturn(CompletableFuture.completedFuture(probe));
+ when(rateLimitCheck.rateLimit(any())).thenReturn(consumptionHolder);
}
-
}
diff --git a/bucket4j-spring-boot-starter/src/test/java/com/giffing/bucket4j/spring/boot/starter/webflux/WebfluxRateLimitFilterTest.java b/bucket4j-spring-boot-starter/src/test/java/com/giffing/bucket4j/spring/boot/starter/webflux/WebfluxRateLimitFilterTest.java
index 24213f5e..aa2b9350 100644
--- a/bucket4j-spring-boot-starter/src/test/java/com/giffing/bucket4j/spring/boot/starter/webflux/WebfluxRateLimitFilterTest.java
+++ b/bucket4j-spring-boot-starter/src/test/java/com/giffing/bucket4j/spring/boot/starter/webflux/WebfluxRateLimitFilterTest.java
@@ -38,50 +38,50 @@ class WebfluxRateLimitFilterTest {
private WebfluxWebFilter filter;
private FilterConfiguration configuration;
- private RateLimitCheck rateLimitCheck1;
- private RateLimitCheck rateLimitCheck2;
- private RateLimitCheck rateLimitCheck3;
+ private RateLimitCheck rateLimitCheck1;
+ private RateLimitCheck rateLimitCheck2;
+ private RateLimitCheck rateLimitCheck3;
private ServerWebExchange exchange;
private WebFilterChain chain;
-
-
+
+
private ServerHttpResponse serverHttpResponse;
-
+
@BeforeEach
- public void setup() throws URISyntaxException {
- rateLimitCheck1 = mock(RateLimitCheck.class);
- rateLimitCheck2 = mock(RateLimitCheck.class);
- rateLimitCheck3 = mock(RateLimitCheck.class);
-
- exchange = Mockito.mock(ServerWebExchange.class);
-
- ServerHttpRequest serverHttpRequest = Mockito.mock(ServerHttpRequest.class);
- URI uri = new URI("url");
- when(serverHttpRequest.getURI()).thenReturn(uri);
+ public void setup() throws URISyntaxException {
+ rateLimitCheck1 = mock(RateLimitCheck.class);
+ rateLimitCheck2 = mock(RateLimitCheck.class);
+ rateLimitCheck3 = mock(RateLimitCheck.class);
+
+ exchange = Mockito.mock(ServerWebExchange.class);
+
+ ServerHttpRequest serverHttpRequest = Mockito.mock(ServerHttpRequest.class);
+ URI uri = new URI("url");
+ when(serverHttpRequest.getURI()).thenReturn(uri);
when(exchange.getRequest()).thenReturn(serverHttpRequest);
-
+
serverHttpResponse = Mockito.mock(ServerHttpResponse.class);
- when(exchange.getResponse()).thenReturn(serverHttpResponse);
-
+ when(exchange.getResponse()).thenReturn(serverHttpResponse);
+
chain = Mockito.mock(WebFilterChain.class);
when(chain.filter(exchange)).thenReturn(Mono.empty());
-
- configuration = new FilterConfiguration<>();
- configuration.setRateLimitChecks(Arrays.asList(rateLimitCheck1, rateLimitCheck2, rateLimitCheck3));
- configuration.setUrl(".*");
- filter = new WebfluxWebFilter(configuration);
- }
+
+ configuration = new FilterConfiguration<>();
+ configuration.setRateLimitChecks(Arrays.asList(rateLimitCheck1, rateLimitCheck2, rateLimitCheck3));
+ configuration.setUrl(".*");
+ filter = new WebfluxWebFilter(configuration);
+ }
@Test void should_throw_rate_limit_exception_with_no_remaining_tokens() {
-
+
configuration.setStrategy(RateLimitConditionMatchingStrategy.FIRST);
- rateLimitConfig(0L, rateLimitCheck1);
- HttpHeaders httpHeaders = Mockito.mock(HttpHeaders.class);
- when(serverHttpResponse.getHeaders()).thenReturn(httpHeaders);
-
- AtomicBoolean hasRateLimitError = new AtomicBoolean(false);
+ rateLimitConfig(0L, rateLimitCheck1);
+ HttpHeaders httpHeaders = Mockito.mock(HttpHeaders.class);
+ when(serverHttpResponse.getHeaders()).thenReturn(httpHeaders);
+
+ AtomicBoolean hasRateLimitError = new AtomicBoolean(false);
Mono result = filter.filter(exchange, chain)
.onErrorResume(ReactiveRateLimitException.class, (e) -> {
hasRateLimitError.set(true);
@@ -90,63 +90,63 @@ public void setup() throws URISyntaxException {
result.subscribe();
Assertions.assertTrue(hasRateLimitError.get());
}
-
+
@Test
void should_execute_all_checks_when_using_RateLimitConditionMatchingStrategy_All() throws URISyntaxException {
-
- configuration.setStrategy(RateLimitConditionMatchingStrategy.ALL);
-
- rateLimitConfig(30L, rateLimitCheck1);
- rateLimitConfig(0L, rateLimitCheck2);
- rateLimitConfig(0L, rateLimitCheck3);
-
- HttpHeaders httpHeaders = Mockito.mock(HttpHeaders.class);
- when(serverHttpResponse.getHeaders()).thenReturn(httpHeaders);
-
- Assertions.assertThrows(ReactiveRateLimitException.class, () -> {
- Mono result = filter.filter(exchange, chain);
- result.block();
- });
-
+
+ configuration.setStrategy(RateLimitConditionMatchingStrategy.ALL);
+
+ rateLimitConfig(30L, rateLimitCheck1);
+ rateLimitConfig(0L, rateLimitCheck2);
+ rateLimitConfig(0L, rateLimitCheck3);
+
+ HttpHeaders httpHeaders = Mockito.mock(HttpHeaders.class);
+ when(serverHttpResponse.getHeaders()).thenReturn(httpHeaders);
+
+ Assertions.assertThrows(ReactiveRateLimitException.class, () -> {
+ Mono result = filter.filter(exchange, chain);
+ result.block();
+ });
+
verify(rateLimitCheck1).rateLimit(any());
- verify(rateLimitCheck2).rateLimit(any());
- verify(rateLimitCheck3).rateLimit(any());
+ verify(rateLimitCheck2).rateLimit(any());
+ verify(rateLimitCheck3).rateLimit(any());
}
@Test
void should_execute_only_one_check_when_using_RateLimitConditionMatchingStrategy_FIRST() {
-
- configuration.setStrategy(RateLimitConditionMatchingStrategy.FIRST);
-
- rateLimitConfig(30L, rateLimitCheck1);
- rateLimitConfig(0L, rateLimitCheck2);
- rateLimitConfig(10L, rateLimitCheck3);
-
- HttpHeaders httpHeaders = Mockito.mock(HttpHeaders.class);
- when(serverHttpResponse.getHeaders()).thenReturn(httpHeaders);
-
- Mono result = filter.filter(exchange, chain);
+
+ configuration.setStrategy(RateLimitConditionMatchingStrategy.FIRST);
+
+ rateLimitConfig(30L, rateLimitCheck1);
+ rateLimitConfig(0L, rateLimitCheck2);
+ rateLimitConfig(10L, rateLimitCheck3);
+
+ HttpHeaders httpHeaders = Mockito.mock(HttpHeaders.class);
+ when(serverHttpResponse.getHeaders()).thenReturn(httpHeaders);
+
+ Mono result = filter.filter(exchange, chain);
result.block();
-
+
final ArgumentCaptor captor = ArgumentCaptor.forClass(String.class);
- verify(httpHeaders, times(1)).set(any(), captor.capture());
-
- List values = captor.getAllValues();
- Assertions.assertEquals("30", values.stream().findFirst().get());
-
- verify(rateLimitCheck1).rateLimit(any());
- verify(rateLimitCheck2).rateLimit(any());
- verify(rateLimitCheck3).rateLimit(any());
+ verify(httpHeaders, times(1)).set(any(), captor.capture());
+
+ List values = captor.getAllValues();
+ Assertions.assertEquals("30", values.stream().findFirst().get());
+
+ verify(rateLimitCheck1, times(1)).rateLimit(any());
+ verify(rateLimitCheck2, times(0)).rateLimit(any());
+ verify(rateLimitCheck3, times(0)).rateLimit(any());
}
- private void rateLimitConfig(Long remainingTokens, RateLimitCheck rateLimitCheck) {
+ private void rateLimitConfig(Long remainingTokens, RateLimitCheck rateLimitCheck) {
ConsumptionProbeHolder consumptionHolder = Mockito.mock(ConsumptionProbeHolder.class);
- ConsumptionProbe probe = Mockito.mock(ConsumptionProbe.class);
- when(probe.isConsumed()).thenReturn(remainingTokens > 0 ? true : false);
+ ConsumptionProbe probe = Mockito.mock(ConsumptionProbe.class);
+ when(probe.isConsumed()).thenReturn(remainingTokens > 0);
when(probe.getRemainingTokens()).thenReturn(remainingTokens);
when(consumptionHolder.getConsumptionProbeCompletableFuture())
- .thenReturn(CompletableFuture.completedFuture(probe));
- when(rateLimitCheck.rateLimit(any())).thenReturn(consumptionHolder);
+ .thenReturn(CompletableFuture.completedFuture(probe));
+ when(rateLimitCheck.rateLimit(any())).thenReturn(consumptionHolder);
}
-
+
}
diff --git a/examples/ehcache/pom.xml b/examples/ehcache/pom.xml
index b73429a4..f876405e 100644
--- a/examples/ehcache/pom.xml
+++ b/examples/ehcache/pom.xml
@@ -12,6 +12,7 @@
true
+ 4.0.4
@@ -58,12 +59,12 @@
com.sun.xml.bind
jaxb-core
- 4.0.3
+ ${jaxb-core.version}
com.sun.xml.bind
jaxb-impl
- 4.0.3
+ ${jaxb-core.version}
org.ehcache
diff --git a/examples/ehcache/src/main/java/com/giffing/bucket4j/spring/boot/starter/examples/ehcache/config/security/SecurityConfig.java b/examples/ehcache/src/main/java/com/giffing/bucket4j/spring/boot/starter/examples/ehcache/config/security/SecurityConfig.java
index 7737da55..5f5fc65d 100644
--- a/examples/ehcache/src/main/java/com/giffing/bucket4j/spring/boot/starter/examples/ehcache/config/security/SecurityConfig.java
+++ b/examples/ehcache/src/main/java/com/giffing/bucket4j/spring/boot/starter/examples/ehcache/config/security/SecurityConfig.java
@@ -3,6 +3,7 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
@@ -14,16 +15,20 @@ public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
- http.authorizeHttpRequests().requestMatchers("/unsecure").permitAll();
- http.authorizeHttpRequests().requestMatchers("/login").permitAll();
- http.authorizeHttpRequests().requestMatchers("/secure").hasAnyRole("ADMIN", "USER");
- http.authorizeHttpRequests().requestMatchers("/hello").permitAll();
- http.authorizeHttpRequests().requestMatchers("/filters/**").permitAll();
- return http.csrf().disable().build();
+ http.csrf(AbstractHttpConfigurer::disable);
+ http.authorizeHttpRequests(auth -> {
+ auth.requestMatchers("/unsecure").permitAll();
+ auth.requestMatchers("/actuator/*").permitAll();
+ auth.requestMatchers("/login").permitAll();
+ auth.requestMatchers("/filters/**").permitAll();
+ auth.requestMatchers("/hello").permitAll();
+ auth.requestMatchers("/secure").hasAnyRole("ADMIN", "USER");
+ });
+ return http.build();
}
@Bean
- public UserDetailsService inMemoryUser() throws Exception {
+ public UserDetailsService inMemoryUser() {
UserDetails user = User.builder()
.username("admin")
.password("123")
diff --git a/examples/redis-lettuce/pom.xml b/examples/redis-lettuce/pom.xml
index 63863e2c..6429103c 100644
--- a/examples/redis-lettuce/pom.xml
+++ b/examples/redis-lettuce/pom.xml
@@ -17,7 +17,7 @@
17
UTF-8
1.6.4
- 6.2.6.RELEASE
+ 6.3.0.RELEASE
diff --git a/examples/webflux-infinispan/pom.xml b/examples/webflux-infinispan/pom.xml
index 3831cd7c..73a6a364 100644
--- a/examples/webflux-infinispan/pom.xml
+++ b/examples/webflux-infinispan/pom.xml
@@ -45,13 +45,7 @@
org.infinispan
- infinispan-spring-boot-starter-embedded
-
-
- org.infinispan
- infinispan-core
-
-
+ infinispan-spring-boot3-starter-embedded
org.infinispan
diff --git a/examples/webflux-infinispan/src/main/resources/infinispan.xml b/examples/webflux-infinispan/src/main/resources/infinispan.xml
index ad8fc0b0..0e2861d0 100644
--- a/examples/webflux-infinispan/src/main/resources/infinispan.xml
+++ b/examples/webflux-infinispan/src/main/resources/infinispan.xml
@@ -6,5 +6,7 @@
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index ea3588e2..678d4524 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,7 +12,7 @@
org.springframework.boot
spring-boot-starter-parent
- 3.1.4
+ 3.1.6
@@ -25,11 +25,10 @@
examples/gateway
examples/redis-jedis
examples/redis-lettuce
+
examples/webflux-infinispan
- -->
https://github.com/MarcGiffing/bucket4j-spring-boot-starter
@@ -45,12 +44,12 @@
bucket4j-spring-boot-starter-parent-0.3.4
- 0.10.0-SNAPSHOT
+ 0.10.1
UTF-8
UTF-8
17
- 8.4.0
- 4.0.7
+ 8.7.0
+ 4.0.8