diff --git a/README.adoc b/README.adoc index 9d84e36e..48da753d 100644 --- a/README.adoc +++ b/README.adoc @@ -27,7 +27,92 @@ image::https://codecov.io/gh/spring-cloud/spring-cloud-gateway/branch/main/graph [[building]] = Building -Unresolved directive in - include::https:///raw.githubusercontent.com/spring-cloud/spring-cloud-build/main/docs/modules/ROOT/partials/building.adoc[] +:jdkversion: 17 + +[[basic-compile-and-test]] +== Basic Compile and Test + +To build the source you will need to install JDK {jdkversion}. + +Spring Cloud uses Maven for most build-related activities, and you +should be able to get off the ground quite quickly by cloning the +project you are interested in and typing + +---- +$ ./mvnw install +---- + +NOTE: You can also install Maven (>=3.3.3) yourself and run the `mvn` command +in place of `./mvnw` in the examples below. If you do that you also +might need to add `-P spring` if your local Maven settings do not +contain repository declarations for spring pre-release artifacts. + +NOTE: Be aware that you might need to increase the amount of memory +available to Maven by setting a `MAVEN_OPTS` environment variable with +a value like `-Xmx512m -XX:MaxPermSize=128m`. We try to cover this in +the `.mvn` configuration, so if you find you have to do it to make a +build succeed, please raise a ticket to get the settings added to +source control. + +The projects that require middleware (i.e. Redis) for testing generally +require that a local instance of [Docker](https://www.docker.com/get-started) is installed and running. + +[[documentation]] +== Documentation + +The spring-cloud-build module has a "docs" profile, and if you switch +that on it will try to build asciidoc sources using https://docs.antora.org/antora/latest/[Antora] from +`modules/ROOT/`. + +As part of that process it will look for a +`docs/src/main/asciidoc/README.adoc` and process it by loading all the includes, but not +parsing or rendering it, just copying it to `${main.basedir}` +(defaults to `$\{basedir}`, i.e. the root of the project). If there are +any changes in the README it will then show up after a Maven build as +a modified file in the correct place. Just commit it and push the change. + +[[working-with-the-code]] +== Working with the code +If you don't have an IDE preference we would recommend that you use +https://www.springsource.com/developer/sts[Spring Tools Suite] or +https://eclipse.org[Eclipse] when working with the code. We use the +https://eclipse.org/m2e/[m2eclipse] eclipse plugin for maven support. Other IDEs and tools +should also work without issue as long as they use Maven 3.3.3 or better. + +[[activate-the-spring-maven-profile]] +=== Activate the Spring Maven profile +Spring Cloud projects require the 'spring' Maven profile to be activated to resolve +the spring milestone and snapshot repositories. Use your preferred IDE to set this +profile to be active, or you may experience build errors. + +[[importing-into-eclipse-with-m2eclipse]] +=== Importing into eclipse with m2eclipse +We recommend the https://eclipse.org/m2e/[m2eclipse] eclipse plugin when working with +eclipse. If you don't already have m2eclipse installed it is available from the "eclipse +marketplace". + +NOTE: Older versions of m2e do not support Maven 3.3, so once the +projects are imported into Eclipse you will also need to tell +m2eclipse to use the right profile for the projects. If you +see many different errors related to the POMs in the projects, check +that you have an up to date installation. If you can't upgrade m2e, +add the "spring" profile to your `settings.xml`. Alternatively you can +copy the repository settings from the "spring" profile of the parent +pom into your `settings.xml`. + +[[importing-into-eclipse-without-m2eclipse]] +=== Importing into eclipse without m2eclipse +If you prefer not to use m2eclipse you can generate eclipse project metadata using the +following command: + +[indent=0] +---- + $ ./mvnw eclipse:eclipse +---- + +The generated eclipse projects can be imported by selecting `import existing projects` +from the `file` menu. + [[contributing]] = Contributing @@ -224,7 +309,7 @@ Spring Cloud Build brings along the `basepom:duplicate-finder-maven-plugin`, th [[duplicate-finder-configuration]] === Duplicate Finder configuration -Duplicate finder is *enabled by default* and will run in the `verify` phase of your Maven build, but it will only take effect in your project if you add the `duplicate-finder-maven-plugin` to the `build` section of the projecst's `pom.xml`. +Duplicate finder is *enabled by default* and will run in the `verify` phase of your Maven build, but it will only take effect in your project if you add the `duplicate-finder-maven-plugin` to the `build` section of the project's `pom.xml`. .pom.xml [source,xml] diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/addrequestheader.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/addrequestheader.adoc index d189f531..61974ef4 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/addrequestheader.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/addrequestheader.adoc @@ -30,8 +30,10 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsAddReqHeader() { - return route(GET("/red"), http("https://example.org")) - .before(addRequestHeader("X-Request-red", "blue")); + return route("addRequestHeader") + .route(GET("/red"), http("https://example.org")) + .before(addRequestHeader("X-Request-red", "blue")) + .build(); } } ---- @@ -50,8 +52,10 @@ class RouteConfiguration { @Bean public RouterFunction gatewayRouterFunctionsAddReqHeader() { - return route(GET("/red/{segment}"), http("https://example.org")) - .before(addRequestHeader("X-Request-red", "blue-{segment}")); + return route("addRequestHeader") + .route(GET("/red/{segment}"), http("https://example.org")) + .before(addRequestHeader("X-Request-red", "blue-{segment}")) + .build(); } } ---- diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/writing-custom-predicates-and-filters.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/writing-custom-predicates-and-filters.adoc index fdabf35d..6735aa08 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/writing-custom-predicates-and-filters.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/writing-custom-predicates-and-filters.adoc @@ -29,7 +29,7 @@ The `RequestPredicate` implementations in Spring WebMvc.fn https://docs.spring.i .SampleRequestPredicates.java [source,java] ---- -import org.springframework.web.reactive.function.server.RequestPredicate; +import org.springframework.web.servlet.function.RequestPredicate; class SampleRequestPredicates { public static RequestPredicate headerExists(String header) { diff --git a/docs/package.json b/docs/package.json index 567c1f3a..6c97a4cc 100644 --- a/docs/package.json +++ b/docs/package.json @@ -4,7 +4,7 @@ "@antora/atlas-extension": "1.0.0-alpha.2", "@antora/collector-extension": "1.0.1", "@asciidoctor/tabs": "1.0.0-beta.6", - "@springio/antora-extensions": "1.14.2", - "@springio/asciidoctor-extensions": "1.0.0-alpha.14" + "@springio/antora-extensions": "1.14.4", + "@springio/asciidoctor-extensions": "1.0.0-alpha.16" } } diff --git a/docs/src/main/asciidoc/README.adoc b/docs/src/main/asciidoc/README.adoc index c3ef9823..7a3af2cd 100644 --- a/docs/src/main/asciidoc/README.adoc +++ b/docs/src/main/asciidoc/README.adoc @@ -20,7 +20,7 @@ image::https://codecov.io/gh/spring-cloud/spring-cloud-gateway/branch/main/graph [[building]] = Building -include::https:///raw.githubusercontent.com/spring-cloud/spring-cloud-build/main/docs/modules/ROOT/partials/building.adoc[] +include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/main/docs/modules/ROOT/partials/building.adoc[] [[contributing]] = Contributing diff --git a/spring-cloud-gateway-integration-tests/grpc/pom.xml b/spring-cloud-gateway-integration-tests/grpc/pom.xml index 39aefb18..6842696a 100644 --- a/spring-cloud-gateway-integration-tests/grpc/pom.xml +++ b/spring-cloud-gateway-integration-tests/grpc/pom.xml @@ -12,7 +12,7 @@ 3.25.1 - 1.70.0 + 1.71.0 diff --git a/spring-cloud-gateway-server/pom.xml b/spring-cloud-gateway-server/pom.xml index b893e88b..2a61283f 100644 --- a/spring-cloud-gateway-server/pom.xml +++ b/spring-cloud-gateway-server/pom.xml @@ -16,7 +16,7 @@ Spring Cloud Gateway Server ${basedir}/.. - 1.70.0 + 1.71.0 1.0.0 diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java index 85767b84..72c55d60 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java @@ -210,6 +210,7 @@ public class GatewayAutoConfiguration { * @deprecated in favour of * {@link org.springframework.cloud.gateway.support.config.KeyValueConverter} */ + @Deprecated @Bean public org.springframework.cloud.gateway.support.KeyValueConverter deprecatedKeyValueConverter() { return new org.springframework.cloud.gateway.support.KeyValueConverter(); diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/QueryRoutePredicateFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/QueryRoutePredicateFactory.java index 1a7fd9b1..f8c1425f 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/QueryRoutePredicateFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/QueryRoutePredicateFactory.java @@ -20,6 +20,7 @@ import java.util.Arrays; import java.util.List; import java.util.function.Predicate; +import jakarta.validation.constraints.AssertTrue; import jakarta.validation.constraints.NotEmpty; import org.springframework.util.StringUtils; @@ -40,13 +41,18 @@ public class QueryRoutePredicateFactory extends AbstractRoutePredicateFactory shortcutFieldOrder() { - return Arrays.asList(PARAM_KEY, REGEXP_KEY); + return Arrays.asList(PARAM_KEY, REGEXP_KEY, PREDICATE_KEY); } @Override @@ -54,7 +60,7 @@ public class QueryRoutePredicateFactory extends AbstractRoutePredicateFactory predicate = config.predicate; + if (StringUtils.hasText(config.regexp)) { + predicate = value -> value.matches(config.regexp); + } for (String value : values) { - if (value != null && value.matches(config.regexp)) { + if (value != null && predicate.test(value)) { return true; } } @@ -90,8 +101,10 @@ public class QueryRoutePredicateFactory extends AbstractRoutePredicateFactory predicate; + public String getParam() { - return param; + return this.param; } public Config setParam(String param) { @@ -100,7 +113,7 @@ public class QueryRoutePredicateFactory extends AbstractRoutePredicateFactory getPredicate() { + return this.predicate; + } + + public Config setPredicate(Predicate predicate) { + this.predicate = predicate; + return this; + } + + /** + * Enforces the validation done on predicate configuration: {@link #regexp} and + * {@link #predicate} can't be both set at runtime. + * @return false if {@link #regexp} and {@link #predicate} are both + * set in this predicate factory configuration + */ + @AssertTrue + public boolean isValid() { + return !(StringUtils.hasText(this.regexp) && this.predicate != null); + } + } } diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/PredicateSpec.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/PredicateSpec.java index 7068c68a..fb70de68 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/PredicateSpec.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/PredicateSpec.java @@ -204,6 +204,18 @@ public class PredicateSpec extends UriSpec { getBean(ReadBodyRoutePredicateFactory.class).applyAsync(c -> c.setPredicate(inClass, predicate))); } + /** + * A predicate that checks if a query parameter value matches criteria of a given + * predicate. + * @param param the query parameter name + * @param predicate a predicate to check the value of the param + * @return a {@link BooleanSpec} to be used to add logical operators + */ + public BooleanSpec query(String param, Predicate predicate) { + return asyncPredicate( + getBean(QueryRoutePredicateFactory.class).applyAsync(c -> c.setParam(param).setPredicate(predicate))); + } + /** * A predicate that checks if a query parameter matches a regular expression. * @param param the query parameter name diff --git a/spring-cloud-gateway-server/src/main/resources/META-INF/scripts/request_rate_limiter.lua b/spring-cloud-gateway-server/src/main/resources/META-INF/scripts/request_rate_limiter.lua index 7959d95e..37033036 100644 --- a/spring-cloud-gateway-server/src/main/resources/META-INF/scripts/request_rate_limiter.lua +++ b/spring-cloud-gateway-server/src/main/resources/META-INF/scripts/request_rate_limiter.lua @@ -2,59 +2,26 @@ redis.replicate_commands() local tokens_key = KEYS[1] local timestamp_key = KEYS[2] ---redis.log(redis.LOG_WARNING, "tokens_key " .. tokens_key) local rate = tonumber(ARGV[1]) local capacity = tonumber(ARGV[2]) -local now = tonumber(ARGV[3]) +local now = tonumber(ARGV[3]) or redis.call('TIME')[1] local requested = tonumber(ARGV[4]) local fill_time = capacity / rate local ttl = math.floor(fill_time * 2) --- for testing, it should use redis system time in production -if now == nil then - now = redis.call('TIME')[1] -end - ---redis.log(redis.LOG_WARNING, "rate " .. ARGV[1]) ---redis.log(redis.LOG_WARNING, "capacity " .. ARGV[2]) ---redis.log(redis.LOG_WARNING, "now " .. now) ---redis.log(redis.LOG_WARNING, "requested " .. ARGV[4]) ---redis.log(redis.LOG_WARNING, "filltime " .. fill_time) ---redis.log(redis.LOG_WARNING, "ttl " .. ttl) - -local last_tokens = tonumber(redis.call("get", tokens_key)) -if last_tokens == nil then - last_tokens = capacity -end ---redis.log(redis.LOG_WARNING, "last_tokens " .. last_tokens) - -local last_refreshed = tonumber(redis.call("get", timestamp_key)) -if last_refreshed == nil then - last_refreshed = 0 -end ---redis.log(redis.LOG_WARNING, "last_refreshed " .. last_refreshed) +local last_tokens = tonumber(redis.call("get", tokens_key)) or capacity +local last_refreshed = tonumber(redis.call("get", timestamp_key)) or 0 local delta = math.max(0, now-last_refreshed) local filled_tokens = math.min(capacity, last_tokens+(delta*rate)) local allowed = filled_tokens >= requested -local new_tokens = filled_tokens -local allowed_num = 0 -if allowed then - new_tokens = filled_tokens - requested - allowed_num = 1 -end - ---redis.log(redis.LOG_WARNING, "delta " .. delta) ---redis.log(redis.LOG_WARNING, "filled_tokens " .. filled_tokens) ---redis.log(redis.LOG_WARNING, "allowed_num " .. allowed_num) ---redis.log(redis.LOG_WARNING, "new_tokens " .. new_tokens) +local new_tokens = allowed and filled_tokens - requested or filled_tokens if ttl > 0 then redis.call("setex", tokens_key, ttl, new_tokens) redis.call("setex", timestamp_key, ttl, now) end --- return { allowed_num, new_tokens, capacity, filled_tokens, requested, new_tokens } -return { allowed_num, new_tokens } +return { allowed and 1 or 0, new_tokens } \ No newline at end of file diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/QueryRoutePredicateFactoryPredicateTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/QueryRoutePredicateFactoryPredicateTests.java new file mode 100644 index 00000000..69765659 --- /dev/null +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/QueryRoutePredicateFactoryPredicateTests.java @@ -0,0 +1,141 @@ +/* + * Copyright 2013-2024 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.gateway.handler.predicate; + +import java.util.function.Predicate; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.system.CapturedOutput; +import org.springframework.boot.test.system.OutputCaptureExtension; +import org.springframework.cloud.gateway.handler.predicate.QueryRoutePredicateFactory.Config; +import org.springframework.cloud.gateway.route.RouteLocator; +import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; +import org.springframework.cloud.gateway.support.HasConfig; +import org.springframework.cloud.gateway.test.BaseWebClientTests; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.web.server.ServerWebExchange; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +/** + * Test class for {@link QueryRoutePredicateFactory} for predicate parameter. + * + * @see QueryRoutePredicateFactory + */ +@SpringBootTest(webEnvironment = RANDOM_PORT) +@DirtiesContext +@ExtendWith(OutputCaptureExtension.class) +public class QueryRoutePredicateFactoryPredicateTests extends BaseWebClientTests { + + @Test + public void noQueryParamWorks(CapturedOutput output) { + this.testClient.get() + .uri("/get") + .exchange() + .expectStatus() + .isOk() + .expectHeader() + .valueEquals(ROUTE_ID_HEADER, "default_path_to_httpbin"); + assertThat(output).doesNotContain("Error applying predicate for route: foo_query_param"); + } + + @Test + public void queryParamPredicateTrue() { + this.testClient.get() + .uri("/get?foo=1234567") + .exchange() + .expectStatus() + .isOk() + .expectHeader() + .valueEquals(ROUTE_ID_HEADER, "foo_query_param"); + } + + @Test + public void queryParamPredicateFalse(CapturedOutput output) { + this.testClient.get() + .uri("/get?foo=123") + .exchange() + .expectStatus() + .isOk() + .expectHeader() + .valueEquals(ROUTE_ID_HEADER, "default_path_to_httpbin"); + assertThat(output).doesNotContain("Error applying predicate for route: foo_query_param"); + } + + @Test + public void emptyQueryParamWorks(CapturedOutput output) { + this.testClient.get() + .uri("/get?foo") + .exchange() + .expectStatus() + .isOk() + .expectHeader() + .valueEquals(ROUTE_ID_HEADER, "default_path_to_httpbin"); + assertThat(output).doesNotContain("Error applying predicate for route: foo_query_param"); + } + + @Test + public void testConfig() { + Config config = new Config(); + config.setParam("query_param"); + Predicate predicate = new QueryRoutePredicateFactory().apply(config); + assertThat(predicate).isInstanceOf(HasConfig.class); + assertThat(config).isSameAs(((HasConfig) predicate).getConfig()); + } + + @Test + public void toStringFormat() { + Config config = new Config(); + config.setParam("query_param"); + Predicate predicate = new QueryRoutePredicateFactory().apply(config); + assertThat(predicate.toString()).contains("Query: param=query_param"); + } + + @EnableAutoConfiguration + @SpringBootConfiguration + @Import(DefaultTestConfig.class) + public static class TestConfig { + + private static final int PARAM_LENGTH = 5; + + @Value("${test.uri}") + private String uri; + + @Bean + RouteLocator queryRouteLocator(RouteLocatorBuilder builder) { + return builder.routes() + .route("foo_query_param", + r -> r.query("foo", queryParamPredicate()).filters(f -> f.prefixPath("/httpbin")).uri(this.uri)) + .build(); + } + + private Predicate queryParamPredicate() { + return p -> p == null ? false : p.length() > PARAM_LENGTH; + } + + } + +} diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/QueryRoutePredicateFactoryTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/QueryRoutePredicateFactoryTests.java index 4506e20f..6a4c7264 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/QueryRoutePredicateFactoryTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/QueryRoutePredicateFactoryTests.java @@ -43,6 +43,11 @@ import org.springframework.test.annotation.DirtiesContext; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; +/** + * Test class for {@link QueryRoutePredicateFactory} for regex parameter. + * + * @see QueryRoutePredicateFactory + */ @SpringBootTest(webEnvironment = RANDOM_PORT) @DirtiesContext @ExtendWith(OutputCaptureExtension.class) diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/AdhocTestSuite.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/AdhocTestSuite.java index 5d1bf14f..38041174 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/AdhocTestSuite.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/AdhocTestSuite.java @@ -46,6 +46,7 @@ import static org.junit.Assume.assumeThat; org.springframework.cloud.gateway.handler.predicate.MethodRoutePredicateFactoryTests.class, org.springframework.cloud.gateway.handler.predicate.BetweenRoutePredicateFactoryTests.class, org.springframework.cloud.gateway.handler.predicate.QueryRoutePredicateFactoryTests.class, + org.springframework.cloud.gateway.handler.predicate.QueryRoutePredicateFactoryPredicateTests.class, org.springframework.cloud.gateway.handler.predicate.WeightRoutePredicateFactoryIntegrationTests.class, org.springframework.cloud.gateway.handler.predicate.HeaderRoutePredicateFactoryTests.class, org.springframework.cloud.gateway.handler.predicate.BeforeRoutePredicateFactoryTests.class, diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/CustomBlockHoundIntegrationTest.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/CustomBlockHoundIntegrationTest.java index 228679ac..308c0b93 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/CustomBlockHoundIntegrationTest.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/CustomBlockHoundIntegrationTest.java @@ -17,6 +17,7 @@ package org.springframework.cloud.gateway.test; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledForJreRange; import org.junit.jupiter.api.condition.JRE; @@ -30,6 +31,8 @@ public class CustomBlockHoundIntegrationTest { @Test @DisabledForJreRange(min = JRE.JAVA_18) + // Disable this test for now flaky on GitHub Actions + @Disabled public void shouldThrowErrorForBlockingCallWithCustomBlockHoundIntegration() { Assertions.assertThrows(RuntimeException.class, () -> Mono.fromCallable(() -> { Thread.sleep(1);