From c089a3a6fe6075374be13b41bceef43899a91970 Mon Sep 17 00:00:00 2001 From: Stian Thorgersen Date: Wed, 19 Nov 2025 20:43:42 +0100 Subject: [PATCH] Add support to use kcw with remote test server Closes #44312 Signed-off-by: stianst --- misc/scripts/kcw | 18 +++++ test-framework/HOW_TO_RUN.md | 7 +- .../server/RemoteKeycloakServer.java | 70 +++++++++++++------ 3 files changed, 70 insertions(+), 25 deletions(-) diff --git a/misc/scripts/kcw b/misc/scripts/kcw index 9c6fbecbbe1..cb2d40da8af 100755 --- a/misc/scripts/kcw +++ b/misc/scripts/kcw @@ -31,6 +31,10 @@ while [ "$1" != "" ]; do echo " rel install latest release" echo " rel[=version] install specific version" echo "" + echo "Environment variables:" + echo " KCW_PROVIDERS comma separated list of providers to install" + echo " KCW_CONFIGS comma separated list of config files to install" + echo "" echo "Examples:" echo " Start existing install: kcw start-dev" echo " Install nightly and start: kcw nightly start-dev --cluster=none" @@ -125,6 +129,20 @@ if [ "$INSTALL" != "" ]; then fi fi +if [ "$KCW_PROVIDERS" != "" ]; then + for PROVIDER in $(echo "$KCW_PROVIDERS" | tr "," "\n"); do + cp "$PROVIDER" $KC_DIR/providers/ + echo "Installed provider: $PROVIDER" + done +fi + +if [ "$KCW_CONFIGS" != "" ]; then + for CONFIG in $(echo "$KCW_CONFIGS" | tr "," "\n"); do + cp "$CONFIG" $KC_DIR/conf/ + echo "Installed config file: $CONFIG" + done +fi + if [ "$ARGS" != "" ]; then echo "" echo "-------------------------------------------------------------------------------------------" diff --git a/test-framework/HOW_TO_RUN.md b/test-framework/HOW_TO_RUN.md index dbfc0512c7e..9787d9311bb 100644 --- a/test-framework/HOW_TO_RUN.md +++ b/test-framework/HOW_TO_RUN.md @@ -101,9 +101,10 @@ Valid values: Configuration: -| Value | Description | -|---------------------------------------------------|------------------------------------------------------------------------| -| `kc.test.server.config` / `KC_TEST_SERVER_CONFIG` | The name of a KeycloakServerConfig class to use when running the tests | +| Value | Description | +|---------------------------------------------------|----------------------------------------------------------------------------------------| +| `kc.test.server.config` / `KC_TEST_SERVER_CONFIG` | The name of a KeycloakServerConfig class to use when running the tests | +| `kc.test.server.kcw` / `KC_TEST_SERVER_KCW` | Set to a kcw command to use kcw with remote server (see `kcw help` for valid commands) | ### Database diff --git a/test-framework/core/src/main/java/org/keycloak/testframework/server/RemoteKeycloakServer.java b/test-framework/core/src/main/java/org/keycloak/testframework/server/RemoteKeycloakServer.java index a9bf219da44..b1980ecc219 100644 --- a/test-framework/core/src/main/java/org/keycloak/testframework/server/RemoteKeycloakServer.java +++ b/test-framework/core/src/main/java/org/keycloak/testframework/server/RemoteKeycloakServer.java @@ -5,19 +5,32 @@ import java.net.URL; import java.nio.file.Path; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import javax.net.ssl.SSLException; +import org.keycloak.it.utils.Maven; +import org.keycloak.testframework.config.Config; + import io.quarkus.maven.dependency.Dependency; +import static java.lang.System.out; + public class RemoteKeycloakServer implements KeycloakServer { private boolean enableTls = false; + private String kcwCommand; + @Override public void start(KeycloakServerConfigBuilder keycloakServerConfigBuilder) { enableTls = keycloakServerConfigBuilder.tlsEnabled(); + kcwCommand = Config.getValueTypeConfig(KeycloakServer.class, "kcw", null, String.class); if (!verifyRunningKeycloak()) { - printStartupInstructions(keycloakServerConfigBuilder); + if (kcwCommand != null) { + printStartupInstructionsKcw(keycloakServerConfigBuilder); + } else { + printStartupInstructionsManual(keycloakServerConfigBuilder); + } waitForStartup(); } } @@ -49,36 +62,49 @@ public class RemoteKeycloakServer implements KeycloakServer { return enableTls; } - private void printStartupInstructions(KeycloakServerConfigBuilder keycloakServerConfigBuilder) { - StringBuilder sb = new StringBuilder(); + private void printStartupInstructionsManual(KeycloakServerConfigBuilder config) { + out.println("Remote Keycloak server is not running on " + getBaseUrl() + ", please start Keycloak with:"); + out.println(); + out.println(String.join(" \\\n", config.toArgs())); + out.println(); - sb.append("Remote Keycloak server is not running on ") - .append(getBaseUrl()) - .append(", please start Keycloak with:\n\n"); - - sb.append(String.join(" \\\n", keycloakServerConfigBuilder.toArgs())); - sb.append("\n\n"); - - Set dependencies = keycloakServerConfigBuilder.toDependencies(); + Set dependencies = config.toDependencies(); if (!dependencies.isEmpty()) { - sb.append("Requested providers:\n"); + out.println("Requested providers:"); for (Dependency d : dependencies) { - sb.append("- "); - sb.append(d.getGroupId()); - sb.append(":"); - sb.append(d.getArtifactId()); - sb.append("\n"); + out.println("* " + d.getGroupId() + ":" + d.getArtifactId()); } + out.println(); } - Set configFiles = keycloakServerConfigBuilder.toConfigFiles(); + + Set configFiles = config.toConfigFiles(); if (!configFiles.isEmpty()) { - sb.append("Copy following config files to your conf directory:\n"); + out.println("Config files:"); for (Path c : configFiles) { - sb.append(c.toAbsolutePath()); - sb.append("\n"); + out.print("* " + c.toAbsolutePath()); } + out.println(); } - System.out.println(sb); + } + + private void printStartupInstructionsKcw(KeycloakServerConfigBuilder config) { + out.println("Remote Keycloak server is not running on " + getBaseUrl() + ", please start Keycloak with:"); + out.println(); + + Set dependencies = config.toDependencies(); + if (!dependencies.isEmpty()) { + String dependencyPaths = dependencies.stream().map(d -> Maven.resolveArtifact(d.getGroupId(), d.getArtifactId()).toString()).collect(Collectors.joining(",")); + out.println("KCW_PROVIDERS=" + dependencyPaths + " \\"); + } + + Set configFiles = config.toConfigFiles(); + if (!configFiles.isEmpty()) { + String configPaths = configFiles.stream().map(p -> p.toAbsolutePath().toString()).collect(Collectors.joining(",")); + out.println("KCW_CONFIGS=" + configPaths + " \\"); + } + + out.println("kcw " + kcwCommand + " " + String.join(" \\\n", config.toArgs())); + out.println(); } private boolean verifyRunningKeycloak() {