Check cluster is correctly formed in ClusteredKeycloakServer

Closes #40858

Signed-off-by: Ryan Emerson <remerson@redhat.com>
Co-authored-by: Pedro Ruivo <pruivo@users.noreply.github.com>
This commit is contained in:
Ryan Emerson 2025-07-04 10:12:51 +01:00 committed by GitHub
parent 919838089f
commit f8f561a435
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 32 additions and 10 deletions

View File

@ -56,6 +56,8 @@ public final class DockerKeycloakDistribution implements KeycloakDistribution {
private static final Logger LOGGER = Logger.getLogger(DockerKeycloakDistribution.class);
public static final int STARTUP_TIMEOUT_SECONDS = 120;
private final boolean debug;
private final boolean manualStop;
private final int requestPort;
@ -102,7 +104,7 @@ public final class DockerKeycloakDistribution implements KeycloakDistribution {
.withEnv(envVars)
.withExposedPorts(exposedPorts)
.withStartupAttempts(1)
.withStartupTimeout(Duration.ofSeconds(120))
.withStartupTimeout(Duration.ofSeconds(STARTUP_TIMEOUT_SECONDS))
.waitingFor(Wait.forListeningPorts(8080));
}

View File

@ -19,17 +19,21 @@ package org.keycloak.testframework.server;
import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.infinispan.server.test.core.CountdownLatchLoggingConsumer;
import org.jboss.logging.Logger;
import org.keycloak.it.utils.DockerKeycloakDistribution;
import org.keycloak.testframework.clustering.LoadBalancer;
import org.keycloak.testframework.database.JBossLogConsumer;
import org.keycloak.testframework.logging.JBossLogConsumer;
import org.testcontainers.images.RemoteDockerImage;
import org.testcontainers.utility.DockerImageName;
import org.testcontainers.utility.LazyFuture;
public class ClusteredKeycloakServer implements KeycloakServer {
private static final String CLUSTER_VIEW_REGEX = ".*ISPN000093.*(?<=\\()(%1$d)(?=\\)).*|.*ISPN000094.*(?<=\\()(%1$d)(?=\\)).*";
private static final boolean MANUAL_STOP = true;
private static final int REQUEST_PORT = 8080;
private static final int MANAGEMENT_PORT = 9000;
@ -49,15 +53,26 @@ public class ClusteredKeycloakServer implements KeycloakServer {
@Override
public void start(KeycloakServerConfigBuilder configBuilder) {
int numServers = containers.length;
CountdownLatchLoggingConsumer clusterLatch = new CountdownLatchLoggingConsumer(numServers, String.format(CLUSTER_VIEW_REGEX, numServers));
String[] imagePeServer = null;
if (images == null || images.isEmpty() || (imagePeServer = images.split(",")).length == 1) {
startContainersWithSameImage(configBuilder, imagePeServer == null ? SNAPSHOT_IMAGE : imagePeServer[0]);
startContainersWithSameImage(configBuilder, imagePeServer == null ? SNAPSHOT_IMAGE : imagePeServer[0], clusterLatch);
} else {
startContainersWithMixedImage(configBuilder, imagePeServer);
startContainersWithMixedImage(configBuilder, imagePeServer, clusterLatch);
}
try {
clusterLatch.await((long) numServers * DockerKeycloakDistribution.STARTUP_TIMEOUT_SECONDS, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
} catch (TimeoutException e) {
throw new RuntimeException("Expected %d cluster members".formatted(numServers), e);
}
}
private void startContainersWithMixedImage(KeycloakServerConfigBuilder configBuilder, String[] imagePeServer) {
private void startContainersWithMixedImage(KeycloakServerConfigBuilder configBuilder, String[] imagePeServer, CountdownLatchLoggingConsumer clusterLatch) {
assert imagePeServer != null;
if (containers.length != imagePeServer.length) {
throw new IllegalArgumentException("The number of containers and the number of images must match");
@ -79,12 +94,12 @@ public class ClusteredKeycloakServer implements KeycloakServer {
copyProvidersAndConfigs(container, configBuilder);
container.setCustomLogConsumer(new JBossLogConsumer(Logger.getLogger("managed.keycloak." + i)));
configureLogConsumers(container, i, clusterLatch);
container.run(configBuilder.toArgs());
}
}
private void startContainersWithSameImage(KeycloakServerConfigBuilder configBuilder, String image) {
private void startContainersWithSameImage(KeycloakServerConfigBuilder configBuilder, String image, CountdownLatchLoggingConsumer clusterLatch) {
int[] exposedPorts = new int[]{REQUEST_PORT, MANAGEMENT_PORT};
LazyFuture<String> imageFuture = image == null || SNAPSHOT_IMAGE.equals(image) ?
defaultImage() :
@ -94,12 +109,16 @@ public class ClusteredKeycloakServer implements KeycloakServer {
containers[i] = container;
copyProvidersAndConfigs(container, configBuilder);
container.setCustomLogConsumer(new JBossLogConsumer(Logger.getLogger("managed.keycloak." + i)));
configureLogConsumers(container, i, clusterLatch);
container.run(configBuilder.toArgs());
}
}
private static void configureLogConsumers(DockerKeycloakDistribution container, int index, CountdownLatchLoggingConsumer clusterLatch) {
var logger = new JBossLogConsumer(Logger.getLogger("managed.keycloak." + index));
container.setCustomLogConsumer(logger.andThen(clusterLatch));
}
private void copyProvidersAndConfigs(DockerKeycloakDistribution container, KeycloakServerConfigBuilder configBuilder) {
for (var dependency : configBuilder.toDependencies()) {
container.copyProvider(dependency.getGroupId(), dependency.getArtifactId());

View File

@ -2,6 +2,7 @@ package org.keycloak.testframework.database;
import org.jboss.logging.Logger;
import org.keycloak.testframework.config.Config;
import org.keycloak.testframework.logging.JBossLogConsumer;
import org.testcontainers.containers.JdbcDatabaseContainer;
import java.io.IOException;

View File

@ -1,4 +1,4 @@
package org.keycloak.testframework.database;
package org.keycloak.testframework.logging;
import org.jboss.logging.Logger;
import org.testcontainers.containers.output.OutputFrame;