diff --git a/pom.xml b/pom.xml index deae3e60e4..60a97aa679 100644 --- a/pom.xml +++ b/pom.xml @@ -45,8 +45,8 @@ jboss-snapshots-repository https://s01.oss.sonatype.org/content/repositories/snapshots/ - 3.7.0.CR1 - 3.7.0.CR1 + 3.7.1 + 3.7.1 ${timestamp} diff --git a/quarkus/config-api/src/main/java/org/keycloak/config/HealthOptions.java b/quarkus/config-api/src/main/java/org/keycloak/config/HealthOptions.java index 44dc44c152..646d8f4c5f 100644 --- a/quarkus/config-api/src/main/java/org/keycloak/config/HealthOptions.java +++ b/quarkus/config-api/src/main/java/org/keycloak/config/HealthOptions.java @@ -9,12 +9,4 @@ public class HealthOptions { .buildTime(true) .build(); - public static final Option HEALTH_CLASSIC_PROBES_ENABLED = new OptionBuilder<>("health-classic-probes-enabled", Boolean.class) - .category(OptionCategory.HEALTH) - .description("If enabled, use the original Quarkus blocking handlers for '/health/ready' and '/health/live' endpoints.") - .defaultValue(Boolean.FALSE) - .buildTime(true) - .hidden() - .build(); - } diff --git a/quarkus/deployment/src/main/java/org/keycloak/quarkus/deployment/KeycloakProcessor.java b/quarkus/deployment/src/main/java/org/keycloak/quarkus/deployment/KeycloakProcessor.java index 1c468711d1..b040d2b5cf 100644 --- a/quarkus/deployment/src/main/java/org/keycloak/quarkus/deployment/KeycloakProcessor.java +++ b/quarkus/deployment/src/main/java/org/keycloak/quarkus/deployment/KeycloakProcessor.java @@ -17,9 +17,12 @@ package org.keycloak.quarkus.deployment; +import io.quarkus.agroal.runtime.health.DataSourceHealthCheck; import io.quarkus.agroal.spi.JdbcDataSourceBuildItem; import io.quarkus.agroal.spi.JdbcDriverBuildItem; +import io.quarkus.arc.deployment.AnnotationsTransformerBuildItem; import io.quarkus.arc.deployment.BuildTimeConditionBuildItem; +import io.quarkus.arc.processor.AnnotationsTransformer; import io.quarkus.bootstrap.logging.InitialConfigurator; import io.quarkus.datasource.deployment.spi.DevServicesDatasourceResultBuildItem; import io.quarkus.deployment.IsDevelopment; @@ -45,6 +48,7 @@ import io.quarkus.runtime.configuration.ProfileManager; import io.quarkus.vertx.http.deployment.RouteBuildItem; import io.quarkus.resteasy.reactive.spi.IgnoreStackMixingBuildItem; import io.smallrye.config.ConfigValue; +import org.eclipse.microprofile.health.Readiness; import org.hibernate.cfg.AvailableSettings; import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor; import org.hibernate.jpa.boot.internal.PersistenceXmlParser; @@ -82,8 +86,6 @@ import org.keycloak.provider.Provider; import org.keycloak.provider.ProviderFactory; import org.keycloak.provider.ProviderManager; import org.keycloak.provider.Spi; -import org.keycloak.quarkus.runtime.integration.health.ReactiveLivenessHandler; -import org.keycloak.quarkus.runtime.integration.health.ReactiveReadinessHandler; import org.keycloak.quarkus.runtime.Environment; import org.keycloak.quarkus.runtime.KeycloakRecorder; import org.keycloak.quarkus.runtime.configuration.Configuration; @@ -95,7 +97,6 @@ import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper; import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers; import org.keycloak.quarkus.runtime.integration.resteasy.KeycloakHandlerChainCustomizer; import org.keycloak.quarkus.runtime.integration.web.NotFoundHandler; -import org.keycloak.quarkus.runtime.services.health.KeycloakReadyAsyncHealthCheck; import org.keycloak.quarkus.runtime.services.health.KeycloakReadyHealthCheck; import org.keycloak.quarkus.runtime.storage.database.jpa.NamedJpaConnectionProviderFactory; import org.keycloak.quarkus.runtime.themes.FlatClasspathThemeResourceProviderFactory; @@ -616,39 +617,29 @@ class KeycloakProcessor { if (healthDisabled) { routes.produce(RouteBuildItem.builder().route(DEFAULT_HEALTH_ENDPOINT.concat("/*")).handler(new NotFoundHandler()).build()); - } else { - // local solution until https://github.com/quarkusio/quarkus/issues/35099 is available in Quarkus - if (!isHealthClassicProbesEnabled()) { - routes.produce(RouteBuildItem.builder().route(DEFAULT_HEALTH_ENDPOINT.concat("/live")).handler(new ReactiveLivenessHandler()).build()); - routes.produce(RouteBuildItem.builder().route(DEFAULT_HEALTH_ENDPOINT.concat("/ready")).handler(new ReactiveReadinessHandler()).build()); - } } boolean metricsDisabled = !isMetricsEnabled(); if (healthDisabled || metricsDisabled) { // disables the single check we provide which depends on metrics enabled - ClassInfo disabledBean1 = index.getIndex() + ClassInfo disabledBean = index.getIndex() .getClassByName(DotName.createSimple(KeycloakReadyHealthCheck.class.getName())); - removeBeans.produce(new BuildTimeConditionBuildItem(disabledBean1.asClass(), false)); - ClassInfo disabledBean2 = index.getIndex() - .getClassByName(DotName.createSimple(KeycloakReadyAsyncHealthCheck.class.getName())); - removeBeans.produce(new BuildTimeConditionBuildItem(disabledBean2.asClass(), false)); - } else { - if (isHealthClassicProbesEnabled()) { - // disable new async check - ClassInfo disabledBean2 = index.getIndex() - .getClassByName(DotName.createSimple(KeycloakReadyAsyncHealthCheck.class.getName())); - removeBeans.produce(new BuildTimeConditionBuildItem(disabledBean2.asClass(), false)); - } else { - // disable old classic check - ClassInfo disabledBean1 = index.getIndex() - .getClassByName(DotName.createSimple(KeycloakReadyHealthCheck.class.getName())); - removeBeans.produce(new BuildTimeConditionBuildItem(disabledBean1.asClass(), false)); - } + removeBeans.produce(new BuildTimeConditionBuildItem(disabledBean.asClass(), false)); } } + // We can't use quarkus.datasource.health.enabled=false as that would remove the DataSourceHealthCheck from CDI and + // it can't be instantiated via constructor as it now includes some field injection points. So we just make it a regular + // bean without the @Readiness annotation so it won't be used as a health check on it's own. + @BuildStep + AnnotationsTransformerBuildItem disableDefaultDataSourceHealthCheck() { + return new AnnotationsTransformerBuildItem(AnnotationsTransformer.appliedToClass() + .whenClass(c -> c.name().equals(DotName.createSimple(DataSourceHealthCheck.class))) + .thenTransform(t -> t.remove( + a -> a.name().equals(DotName.createSimple(Readiness.class))))); + } + @BuildStep void configureResteasy(CombinedIndexBuildItem index, BuildProducer buildTimeConditionBuildItemBuildProducer, @@ -883,10 +874,6 @@ class KeycloakProcessor { return Configuration.getOptionalBooleanValue(NS_KEYCLOAK_PREFIX.concat("health-enabled")).orElse(false); } - private boolean isHealthClassicProbesEnabled() { - return Configuration.getOptionalBooleanValue(NS_KEYCLOAK_PREFIX.concat("health-classic-probes-enabled")).orElse(false); - } - static JdbcDataSourceBuildItem getDefaultDataSource(List jdbcDataSources) { for (JdbcDataSourceBuildItem jdbcDataSource : jdbcDataSources) { if (jdbcDataSource.isDefault()) { diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/HealthPropertyMappers.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/HealthPropertyMappers.java index 75186e88eb..124a7ab382 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/HealthPropertyMappers.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/HealthPropertyMappers.java @@ -14,8 +14,6 @@ final class HealthPropertyMappers { fromOption(HealthOptions.HEALTH_ENABLED) .to("quarkus.health.extensions.enabled") .paramLabel(Boolean.TRUE + "|" + Boolean.FALSE) - .build(), - fromOption(HealthOptions.HEALTH_CLASSIC_PROBES_ENABLED) .build() }; } diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/integration/health/ReactiveHealthHandler.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/integration/health/ReactiveHealthHandler.java deleted file mode 100644 index 7d3d98a198..0000000000 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/integration/health/ReactiveHealthHandler.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2023 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * 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 - * - * http://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.keycloak.quarkus.runtime.integration.health; - -import io.quarkus.smallrye.health.runtime.SmallRyeLivenessHandler; -import io.smallrye.health.SmallRyeHealth; -import io.smallrye.health.SmallRyeHealthReporter; -import io.smallrye.mutiny.Uni; -import io.vertx.core.Handler; -import io.vertx.ext.web.RoutingContext; - -/** - * This adds the possibility to have a non-blocking health handler in Quarkus. - *

- * Without a non-blocking health check, all liveness and readiness probes will enqueue in the worker thread pool. Under high load - * of if there is a lot of blocking IO happening (for example, during Keycloak cluster rebalancing), this leads to probes being queued. - * Queued probes would lead to timeouts unless the timeouts are configured to 10-20 seconds. Reactive probes avoid the enqueueing - * in the worker thread pool for all non-blocking probes, which will be the default for the (otherwise empty) liveness probe. - * For the readiness probe, this depends on the implementation of the specific readiness probes. - *

- * This is a workaround until quarkusio/quarkus#35100 is available - * in a regular Quarkus version. Then these classes can be removed. - * - * @author Alexander Schwartz - */ -public abstract class ReactiveHealthHandler implements Handler { - - @Override - public void handle(RoutingContext context) { - Uni health = getHealth(); - health.subscribe().with(smallRyeHealth -> { - new SmallRyeLivenessHandler() { - @Override - protected SmallRyeHealth getHealth(SmallRyeHealthReporter reporter, RoutingContext ctx) { - return smallRyeHealth; - } - }.handle(context); - }); - } - - protected abstract Uni getHealth(); -} diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/integration/health/ReactiveLivenessHandler.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/integration/health/ReactiveLivenessHandler.java deleted file mode 100644 index c5e5c6db4d..0000000000 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/integration/health/ReactiveLivenessHandler.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2023 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * 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 - * - * http://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.keycloak.quarkus.runtime.integration.health; - -import io.quarkus.arc.Arc; -import io.smallrye.health.SmallRyeHealth; -import io.smallrye.health.SmallRyeHealthReporter; -import io.smallrye.mutiny.Uni; - -/** - * @author Alexander Schwartz - */ -public class ReactiveLivenessHandler extends ReactiveHealthHandler { - - @Override - protected Uni getHealth() { - SmallRyeHealthReporter healthReporter = Arc.container().instance(SmallRyeHealthReporter.class).get(); - return healthReporter.getLivenessAsync(); - } -} diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/integration/health/ReactiveReadinessHandler.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/integration/health/ReactiveReadinessHandler.java deleted file mode 100644 index 5900a2cbbd..0000000000 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/integration/health/ReactiveReadinessHandler.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2023 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * 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 - * - * http://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.keycloak.quarkus.runtime.integration.health; - -import io.quarkus.arc.Arc; -import io.smallrye.health.SmallRyeHealth; -import io.smallrye.health.SmallRyeHealthReporter; -import io.smallrye.mutiny.Uni; - -/** - * @author Alexander Schwartz - */ -public class ReactiveReadinessHandler extends ReactiveHealthHandler { - - @Override - protected Uni getHealth() { - SmallRyeHealthReporter healthReporter = Arc.container().instance(SmallRyeHealthReporter.class).get(); - return healthReporter.getReadinessAsync(); - } -} diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/services/health/KeycloakReadyAsyncHealthCheck.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/services/health/KeycloakReadyAsyncHealthCheck.java deleted file mode 100644 index 8626422431..0000000000 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/services/health/KeycloakReadyAsyncHealthCheck.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2020 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * 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 - * - * http://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.keycloak.quarkus.runtime.services.health; - -import io.agroal.api.AgroalDataSource; -import io.quarkus.agroal.runtime.health.DataSourceHealthCheck; -import io.quarkus.smallrye.health.runtime.QuarkusAsyncHealthCheckFactory; -import io.smallrye.health.api.AsyncHealthCheck; -import io.smallrye.mutiny.Uni; -import jakarta.annotation.PostConstruct; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import org.eclipse.microprofile.health.HealthCheckResponse; -import org.eclipse.microprofile.health.HealthCheckResponseBuilder; -import org.eclipse.microprofile.health.Readiness; - -import java.time.Instant; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import java.util.concurrent.atomic.AtomicReference; - -/** - * Keycloak Healthcheck Readiness Probe. - *

- * Performs a hybrid between the passive and the active mode. If there are no healthy connections in the pool, - * it invokes the standard DataSourceHealthCheck that creates a new connection and checks if it's valid. - *

- * While the check for healthy connections is non-blocking, the standard check is blocking, so it needs to be wrapped. - *

- * When NON_BLOCKING_PROBES is no longer behind a feature flag but the only option, it will replace the - * {@link KeycloakReadyHealthCheck}. - * - * @see Healthcheck API Design - */ -@Readiness -@ApplicationScoped -public class KeycloakReadyAsyncHealthCheck implements AsyncHealthCheck { - - /** As the DataSourceHealthCheck doesn't exist as an application scoped bean, - * create our own instance here which exposes the init() call for the delegate. */ - MyDataSourceHealthCheck delegate; - - private static class MyDataSourceHealthCheck extends DataSourceHealthCheck { - @Override - public void init() { - super.init(); - } - } - - @PostConstruct - protected void init() { - delegate = new MyDataSourceHealthCheck(); - delegate.init(); - } - - /** - * Date formatter, the same as used by Quarkus. This enables users to quickly compare the date printed - * by the probe with the logs. - */ - static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss,SSS").withZone(ZoneId.systemDefault()); - - @Inject - AgroalDataSource agroalDataSource; - - @Inject - QuarkusAsyncHealthCheckFactory healthCheckFactory; - - AtomicReference failingSince = new AtomicReference<>(); - - @Override - public Uni call() { - HealthCheckResponseBuilder builder = HealthCheckResponse.named("Keycloak database connections async health check").up(); - long activeCount = agroalDataSource.getMetrics().activeCount(); - long invalidCount = agroalDataSource.getMetrics().invalidCount(); - if (activeCount < 1 || invalidCount > 0) { - return healthCheckFactory.callSync(() -> { - HealthCheckResponse activeCheckResult = delegate.call(); - if (activeCheckResult.getStatus() == HealthCheckResponse.Status.DOWN) { - builder.down(); - Instant failingTime = failingSince.updateAndGet(this::createInstanceIfNeeded); - builder.withData("Failing since", DATE_FORMATTER.format(failingTime)); - } - return builder.build(); - }); - } else { - failingSince.set(null); - return healthCheckFactory.callAsync(() -> Uni.createFrom().item(builder.build())); - } - } - - Instant createInstanceIfNeeded(Instant instant) { - if (instant == null) { - return Instant.now(); - } - return instant; - } -} \ No newline at end of file diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/services/health/KeycloakReadyHealthCheck.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/services/health/KeycloakReadyHealthCheck.java index d2883eaccf..7d02624063 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/services/health/KeycloakReadyHealthCheck.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/services/health/KeycloakReadyHealthCheck.java @@ -18,12 +18,15 @@ package org.keycloak.quarkus.runtime.services.health; import io.agroal.api.AgroalDataSource; import io.quarkus.agroal.runtime.health.DataSourceHealthCheck; +import io.quarkus.smallrye.health.runtime.QuarkusAsyncHealthCheckFactory; +import io.smallrye.health.api.AsyncHealthCheck; +import io.smallrye.mutiny.Uni; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; import org.eclipse.microprofile.health.HealthCheckResponse; import org.eclipse.microprofile.health.HealthCheckResponseBuilder; import org.eclipse.microprofile.health.Readiness; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; import java.time.Instant; import java.time.ZoneId; import java.time.format.DateTimeFormatter; @@ -31,15 +34,17 @@ import java.util.concurrent.atomic.AtomicReference; /** * Keycloak Healthcheck Readiness Probe. - * + *

* Performs a hybrid between the passive and the active mode. If there are no healthy connections in the pool, - * it invokes the standard DataSourceHealthCheck that creates a new connection and checks if its valid. + * it invokes the standard DataSourceHealthCheck that creates a new connection and checks if it's valid. + *

+ * While the check for healthy connections is non-blocking, the standard check is blocking, so it needs to be wrapped. * * @see Healthcheck API Design */ @Readiness @ApplicationScoped -public class KeycloakReadyHealthCheck extends DataSourceHealthCheck { +public class KeycloakReadyHealthCheck implements AsyncHealthCheck { /** * Date formatter, the same as used by Quarkus. This enables users to quickly compare the date printed @@ -50,24 +55,33 @@ public class KeycloakReadyHealthCheck extends DataSourceHealthCheck { @Inject AgroalDataSource agroalDataSource; + @Inject + QuarkusAsyncHealthCheckFactory healthCheckFactory; + + @Inject + DataSourceHealthCheck dataSourceHealthCheck; + AtomicReference failingSince = new AtomicReference<>(); @Override - public HealthCheckResponse call() { - HealthCheckResponseBuilder builder = HealthCheckResponse.named("Keycloak database connections health check").up(); + public Uni call() { + HealthCheckResponseBuilder builder = HealthCheckResponse.named("Keycloak database connections async health check").up(); long activeCount = agroalDataSource.getMetrics().activeCount(); long invalidCount = agroalDataSource.getMetrics().invalidCount(); if (activeCount < 1 || invalidCount > 0) { - HealthCheckResponse activeCheckResult = super.call(); - if (activeCheckResult.getStatus() == HealthCheckResponse.Status.DOWN) { - builder.down(); - Instant failingTime = failingSince.updateAndGet(this::createInstanceIfNeeded); - builder.withData("Failing since", DATE_FORMATTER.format(failingTime)); - } + return healthCheckFactory.callSync(() -> { + HealthCheckResponse activeCheckResult = dataSourceHealthCheck.call(); + if (activeCheckResult.getStatus() == HealthCheckResponse.Status.DOWN) { + builder.down(); + Instant failingTime = failingSince.updateAndGet(this::createInstanceIfNeeded); + builder.withData("Failing since", DATE_FORMATTER.format(failingTime)); + } + return builder.build(); + }); } else { failingSince.set(null); + return healthCheckFactory.callAsync(() -> Uni.createFrom().item(builder.build())); } - return builder.build(); } Instant createInstanceIfNeeded(Instant instant) { diff --git a/quarkus/runtime/src/main/resources/application.properties b/quarkus/runtime/src/main/resources/application.properties index c369cf48d2..9e9fd36613 100644 --- a/quarkus/runtime/src/main/resources/application.properties +++ b/quarkus/runtime/src/main/resources/application.properties @@ -7,7 +7,6 @@ quarkus.banner.enabled=false # Disable health checks from extensions, since we provide our own (default is true) quarkus.health.extensions.enabled=false -quarkus.datasource.health.enabled=false # Disable http metrics binder as URL parameters are only shown with placeholders for '/resource' URLs, but not # for '/admin' and '/realms'. Neither the IDs of entities nor the realm name should be part of the metric names diff --git a/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/HealthDistTest.java b/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/HealthDistTest.java index 20134a4a3e..2c83578e62 100644 --- a/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/HealthDistTest.java +++ b/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/HealthDistTest.java @@ -80,19 +80,6 @@ public class HealthDistTest { .statusCode(404); } - @Test - @Launch({ "start-dev", "--health-enabled=true", "--metrics-enabled=true", "--health-classic-probes-enabled=true" }) - void testBlockingProbes() { - when().get("/health/live").then() - .statusCode(200); - when().get("/health/ready").then() - .statusCode(200) - .body("checks[0].name", equalTo("Keycloak database connections health check")) - .body("checks.size()", equalTo(1)); - when().get("/lb-check").then() - .statusCode(404); - } - @Test void testUsingRelativePath(KeycloakDistribution distribution) { for (String relativePath : List.of("/auth", "/auth/", "auth")) { diff --git a/testsuite/utils/pom.xml b/testsuite/utils/pom.xml index 96cf6d67e9..8f11485ab1 100755 --- a/testsuite/utils/pom.xml +++ b/testsuite/utils/pom.xml @@ -266,6 +266,7 @@ mysql mysql-connector-java + ${mysql-jdbc.version} compile