From fba558aade5b1164ffd3c9158d7023efc6db07d4 Mon Sep 17 00:00:00 2001 From: sgibb Date: Fri, 23 Jun 2023 23:36:03 -0400 Subject: [PATCH] Updates WeightCalculatorWebFilter to be more testable. Since Random can't be mocked in jdk17+, replace the settable Random with Supplier. Production should still use ThreadLoacalRandom unless the supplier is set. --- .../filter/WeightCalculatorWebFilter.java | 20 ++++++++++++++----- .../WeightCalculatorWebFilterTests.java | 12 ++++------- ...RoutePredicateFactoryIntegrationTests.java | 19 ++++++++---------- ...ightRoutePredicateFactoryYaml404Tests.java | 17 +++++++--------- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/WeightCalculatorWebFilter.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/WeightCalculatorWebFilter.java index 4333043a..977a64fb 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/WeightCalculatorWebFilter.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/WeightCalculatorWebFilter.java @@ -25,6 +25,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -64,7 +65,7 @@ public class WeightCalculatorWebFilter implements WebFilter, Ordered, SmartAppli private final ConfigurationService configurationService; - private Random random = null; + private Supplier randomSupplier = null; private int order = WEIGHT_CALC_FILTER_ORDER; @@ -98,8 +99,13 @@ public class WeightCalculatorWebFilter implements WebFilter, Ordered, SmartAppli this.order = order; } + @Deprecated public void setRandom(Random random) { - this.random = random; + this.randomSupplier = random::nextDouble; + } + + public void setRandomSupplier(Supplier randomSupplier) { + this.randomSupplier = randomSupplier; } @Override @@ -236,9 +242,13 @@ public class WeightCalculatorWebFilter implements WebFilter, Ordered, SmartAppli * Usually, multiple threads accessing the same random object will have some * performance problems, so we can use ThreadLocalRandom by default */ - Random useRandom = this.random; - useRandom = useRandom == null ? ThreadLocalRandom.current() : useRandom; - double r = useRandom.nextDouble(); + double r; + if (this.randomSupplier != null) { + r = randomSupplier.get(); + } + else { + r = ThreadLocalRandom.current().nextDouble(); + } List ranges = config.ranges; diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/WeightCalculatorWebFilterTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/WeightCalculatorWebFilterTests.java index 32fbae2f..adbb0a22 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/WeightCalculatorWebFilterTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/WeightCalculatorWebFilterTests.java @@ -19,11 +19,9 @@ package org.springframework.cloud.gateway.filter; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Random; +import java.util.function.Supplier; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledForJreRange; -import org.junit.jupiter.api.condition.JRE; import org.springframework.cloud.gateway.event.PredicateArgsEvent; import org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter.GroupWeightConfig; @@ -95,20 +93,18 @@ public class WeightCalculatorWebFilterTests { return "route" + i; } - // TODO: modify implementation for testability on JDK17 for Spring 6 @Test - @DisabledForJreRange(min = JRE.JAVA_17) public void testChooseRouteWithRandom() { WeightCalculatorWebFilter filter = createFilter(); filter.addWeightConfig(new WeightConfig("groupa", "route1", 1)); filter.addWeightConfig(new WeightConfig("groupa", "route2", 3)); filter.addWeightConfig(new WeightConfig("groupa", "route3", 6)); - Random random = mock(Random.class); + Supplier random = mock(Supplier.class); - when(random.nextDouble()).thenReturn(0.05).thenReturn(0.2).thenReturn(0.6); + when(random.get()).thenReturn(0.05).thenReturn(0.2).thenReturn(0.6); - filter.setRandom(random); + filter.setRandomSupplier(random); MockServerWebExchange exchange = MockServerWebExchange .from(MockServerHttpRequest.get("http://localhost").build()); diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/WeightRoutePredicateFactoryIntegrationTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/WeightRoutePredicateFactoryIntegrationTests.java index a893948e..a4289bfb 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/WeightRoutePredicateFactoryIntegrationTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/WeightRoutePredicateFactoryIntegrationTests.java @@ -16,12 +16,10 @@ package org.springframework.cloud.gateway.handler.predicate; -import java.util.Random; import java.util.function.Predicate; +import java.util.function.Supplier; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledForJreRange; -import org.junit.jupiter.api.condition.JRE; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -45,21 +43,20 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen @SpringBootTest(webEnvironment = RANDOM_PORT) @DirtiesContext -@DisabledForJreRange(min = JRE.JAVA_17) public class WeightRoutePredicateFactoryIntegrationTests extends BaseWebClientTests { @Autowired private WeightCalculatorWebFilter filter; - private static Random getRandom(double value) { - Random random = mock(Random.class); - when(random.nextDouble()).thenReturn(value); + private static Supplier getRandom(double value) { + Supplier random = mock(Supplier.class); + when(random.get()).thenReturn(value); return random; } @Test public void highWeight() { - filter.setRandom(getRandom(0.9)); + filter.setRandomSupplier(getRandom(0.9)); testClient.get().uri("/get").header(HttpHeaders.HOST, "www.weighthigh.org").exchange().expectStatus().isOk() .expectHeader().valueEquals(ROUTE_ID_HEADER, "weight_high_test"); @@ -67,7 +64,7 @@ public class WeightRoutePredicateFactoryIntegrationTests extends BaseWebClientTe @Test public void lowWeight() { - filter.setRandom(getRandom(0.1)); + filter.setRandomSupplier(getRandom(0.1)); testClient.get().uri("/get").header(HttpHeaders.HOST, "www.weightlow.org").exchange().expectStatus().isOk() .expectHeader().valueEquals(ROUTE_ID_HEADER, "weight_low_test"); @@ -89,9 +86,9 @@ public class WeightRoutePredicateFactoryIntegrationTests extends BaseWebClientTe private String uri; public TestConfig(WeightCalculatorWebFilter filter) { - Random random = getRandom(0.4); + Supplier random = getRandom(0.4); - filter.setRandom(random); + filter.setRandomSupplier(random); } @Bean diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/WeightRoutePredicateFactoryYaml404Tests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/WeightRoutePredicateFactoryYaml404Tests.java index 1fbc524d..c4ff253e 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/WeightRoutePredicateFactoryYaml404Tests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/WeightRoutePredicateFactoryYaml404Tests.java @@ -16,11 +16,9 @@ package org.springframework.cloud.gateway.handler.predicate; -import java.util.Random; +import java.util.function.Supplier; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledForJreRange; -import org.junit.jupiter.api.condition.JRE; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; @@ -40,21 +38,20 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen @SpringBootTest(webEnvironment = RANDOM_PORT) @ActiveProfiles("weights-404") @DirtiesContext -@DisabledForJreRange(min = JRE.JAVA_17) class WeightRoutePredicateFactoryYaml404Tests extends BaseWebClientTests { @Autowired private WeightCalculatorWebFilter filter; - private static Random getRandom(double value) { - Random random = mock(Random.class); - when(random.nextDouble()).thenReturn(value); + private static Supplier getRandom(double value) { + Supplier random = mock(Supplier.class); + when(random.get()).thenReturn(value); return random; } @Test void weightsFromYamlNot404() { - filter.setRandom(getRandom(0.5)); + filter.setRandomSupplier(getRandom(0.5)); testClient.get().uri("/get").header(HttpHeaders.HOST, "www.weight4041.org").exchange().expectStatus().isOk() .expectHeader().valueEquals(ROUTE_ID_HEADER, "weight_first_404_test_1"); @@ -66,9 +63,9 @@ class WeightRoutePredicateFactoryYaml404Tests extends BaseWebClientTests { static class TestConfig { TestConfig(WeightCalculatorWebFilter filter) { - Random random = getRandom(0.4); + Supplier random = getRandom(0.4); - filter.setRandom(random); + filter.setRandomSupplier(random); } }