diff --git a/quarkus/deployment/src/main/java/org/keycloak/quarkus/deployment/IsIntegrationTest.java b/quarkus/deployment/src/main/java/org/keycloak/quarkus/deployment/IsIntegrationTest.java
index 19a3522a5b..765074a298 100644
--- a/quarkus/deployment/src/main/java/org/keycloak/quarkus/deployment/IsIntegrationTest.java
+++ b/quarkus/deployment/src/main/java/org/keycloak/quarkus/deployment/IsIntegrationTest.java
@@ -3,7 +3,7 @@ package org.keycloak.quarkus.deployment;
import io.quarkus.deployment.IsTest;
import io.quarkus.runtime.LaunchMode;
-import static org.keycloak.quarkus.runtime.Environment.LAUNCH_MODE;
+import org.keycloak.quarkus.runtime.Environment;
public class IsIntegrationTest extends IsTest {
@@ -13,7 +13,7 @@ public class IsIntegrationTest extends IsTest {
@Override
public boolean getAsBoolean() {
- return super.getAsBoolean() && (System.getProperty(LAUNCH_MODE) != null && System.getProperty(LAUNCH_MODE).equals("test"));
+ return super.getAsBoolean() && Environment.isTestLaunchMode();
}
}
diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/Environment.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/Environment.java
index 19e852e207..f4b56839f4 100644
--- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/Environment.java
+++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/Environment.java
@@ -18,7 +18,6 @@
package org.keycloak.quarkus.runtime;
import static org.keycloak.quarkus.runtime.configuration.Configuration.getBuildTimeProperty;
-import static org.keycloak.quarkus.runtime.configuration.Configuration.getConfig;
import java.io.File;
import java.io.FilenameFilter;
@@ -177,10 +176,6 @@ public final class Environment {
})).collect(Collectors.toMap(File::getName, Function.identity()));
}
- public static boolean isQuarkusDevMode() {
- return ProfileManager.getLaunchMode().equals(LaunchMode.DEVELOPMENT);
- }
-
public static boolean isTestLaunchMode() {
return "test".equals(System.getProperty(LAUNCH_MODE));
}
@@ -220,7 +215,7 @@ public final class Environment {
}
public static boolean isDistribution() {
- if (isQuarkusDevMode()) {
+ if (LaunchMode.current().isDevOrTest()) {
return false;
}
return getHomeDir() != null;
@@ -233,4 +228,8 @@ public final class Environment {
public static boolean isRebuilt() {
return Boolean.getBoolean("kc.config.built");
}
+
+ public static void setHomeDir(Path path) {
+ System.setProperty("kc.home.dir", path.toFile().getAbsolutePath());
+ }
}
diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/KeycloakMain.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/KeycloakMain.java
index d3a1bf2d14..fa08875f3d 100644
--- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/KeycloakMain.java
+++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/KeycloakMain.java
@@ -38,9 +38,7 @@ import io.quarkus.runtime.Quarkus;
import org.jboss.logging.Logger;
import org.keycloak.Config;
-import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
-import org.keycloak.models.KeycloakTransactionManager;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler;
import org.keycloak.quarkus.runtime.cli.Picocli;
diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/Configuration.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/Configuration.java
index 246e5a6cac..b88a3e1929 100644
--- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/Configuration.java
+++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/Configuration.java
@@ -17,7 +17,6 @@
package org.keycloak.quarkus.runtime.configuration;
-import static io.smallrye.config.common.utils.StringUtil.replaceNonAlphanumericByUnderscores;
import static org.keycloak.quarkus.runtime.Environment.getProfileOrDefault;
import static org.keycloak.quarkus.runtime.cli.Picocli.ARG_PREFIX;
@@ -156,6 +155,22 @@ public final class Configuration {
return sb.toString();
}
+ public static String replaceNonAlphanumericByUnderscores(String name) {
+ int length = name.length();
+ StringBuilder sb = new StringBuilder(length);
+
+ for(int i = 0; i < length; ++i) {
+ char c = name.charAt(i);
+ if (('a' > c || c > 'z') && ('A' > c || c > 'Z') && ('0' > c || c > '9')) {
+ sb.append('_');
+ } else {
+ sb.append(c);
+ }
+ }
+
+ return sb.toString();
+ }
+
private static String getValue(ConfigSource configSource, String name) {
String value = configSource.getValue("%".concat(getProfileOrDefault("prod").concat(".").concat(name)));
diff --git a/quarkus/tests/integration/pom.xml b/quarkus/tests/integration/pom.xml
index f941061503..630db55e47 100644
--- a/quarkus/tests/integration/pom.xml
+++ b/quarkus/tests/integration/pom.xml
@@ -62,6 +62,12 @@
io.quarkus
quarkus-junit5-internal
+
+ junit
+ junit
+ ${junit.version}
+ compile
+
org.keycloak
keycloak-quarkus-dist
@@ -100,6 +106,10 @@
org.testcontainers
mysql
+
+ org.apache.maven.wagon
+ wagon-http-shared
+
diff --git a/quarkus/tests/integration/src/main/java/org/junit/rules/TestRule.java b/quarkus/tests/integration/src/main/java/org/junit/rules/TestRule.java
deleted file mode 100644
index cd0b384371..0000000000
--- a/quarkus/tests/integration/src/main/java/org/junit/rules/TestRule.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package org.junit.rules;
-
-// WORKAROUND: https://github.com/testcontainers/testcontainers-java/issues/970#issuecomment-625044008
-@SuppressWarnings("unused")
-public interface TestRule {
-}
diff --git a/quarkus/tests/integration/src/main/java/org/keycloak/Keycloak.java b/quarkus/tests/integration/src/main/java/org/keycloak/Keycloak.java
new file mode 100644
index 0000000000..34ea552bce
--- /dev/null
+++ b/quarkus/tests/integration/src/main/java/org/keycloak/Keycloak.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2022 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;
+
+import static java.util.concurrent.CompletableFuture.runAsync;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+import org.eclipse.microprofile.config.spi.ConfigProviderResolver;
+import org.keycloak.common.Version;
+import org.keycloak.platform.Platform;
+import org.keycloak.quarkus.runtime.Environment;
+import org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource;
+
+import io.quarkus.bootstrap.app.AugmentAction;
+import io.quarkus.bootstrap.app.CuratedApplication;
+import io.quarkus.bootstrap.app.QuarkusBootstrap;
+import io.quarkus.bootstrap.app.RunningQuarkusApplication;
+import io.quarkus.bootstrap.app.StartupAction;
+import io.quarkus.bootstrap.model.ApplicationModel;
+import io.quarkus.bootstrap.resolver.AppModelResolverException;
+import io.quarkus.bootstrap.resolver.BootstrapAppModelResolver;
+import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException;
+import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver;
+import io.quarkus.bootstrap.workspace.WorkspaceModule;
+import io.quarkus.bootstrap.workspace.WorkspaceModuleId;
+import io.quarkus.maven.dependency.Dependency;
+import io.quarkus.maven.dependency.DependencyBuilder;
+import io.quarkus.runtime.configuration.QuarkusConfigFactory;
+
+public class Keycloak {
+
+ public static class Builder {
+
+ private String version;
+ private Path homeDir;
+ private List dependencies = new ArrayList<>();
+
+ private Builder() {
+
+ }
+
+ public Builder setVersion(String version) {
+ this.version = version;
+ return this;
+ }
+
+ public Builder setHomeDir(Path path) {
+ this.homeDir = path;
+ return this;
+ }
+
+ public Builder addDependency(String groupId, String artifactId, String version) {
+ addDependency(groupId, artifactId, version, null);
+ return this;
+ }
+
+ public Builder addDependency(String groupId, String artifactId, String version, String classifier) {
+ this.dependencies.add(DependencyBuilder.newInstance()
+ .setGroupId(groupId)
+ .setArtifactId(artifactId)
+ .setVersion(version)
+ .setClassifier(classifier)
+ .build());
+ return this;
+ }
+
+ public Keycloak start(String... args) {
+ return start(List.of(args));
+ }
+
+ public Keycloak start(List args) {
+ if (homeDir == null) {
+ homeDir = Platform.getPlatform().getTmpDirectory().toPath();
+ }
+ return new Keycloak(homeDir, version, dependencies).start(args);
+ }
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ private RunningQuarkusApplication application;
+ private ApplicationModel applicationModel;
+ private Path homeDir;
+ private List dependencies;
+
+ public Keycloak() {
+ this(null, Version.VERSION, List.of());
+ }
+
+ public Keycloak(Path homeDir, String version, List dependencies) {
+ this.homeDir = homeDir;
+ this.dependencies = dependencies;
+ try {
+ applicationModel = createApplicationModel(version);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private Keycloak start(List args) {
+ QuarkusBootstrap.Builder builder = QuarkusBootstrap.builder()
+ .setExistingModel(applicationModel)
+ .setApplicationRoot(applicationModel.getApplicationModule().getModuleDir().toPath())
+ .setTargetDirectory(applicationModel.getApplicationModule().getModuleDir().toPath())
+ .setIsolateDeployment(true)
+ .setMode(QuarkusBootstrap.Mode.TEST);
+
+ try (CuratedApplication curated = builder.build().bootstrap()) {
+ AugmentAction action = curated.createAugmentor();
+ Environment.setHomeDir(homeDir);
+ ConfigArgsConfigSource.setCliArgs(args.toArray(new String[0]));
+
+ StartupAction startupAction = action.createInitialRuntimeApplication();
+
+ application = startupAction.runMainClass(args.toArray(new String[0]));
+
+ return this;
+ } catch (Exception cause) {
+ throw new RuntimeException("Fail to start the server", cause);
+ }
+ }
+
+ public void stop() throws TimeoutException {
+ if (isRunning()) {
+ closeApplication();
+ }
+ }
+
+ private ApplicationModel createApplicationModel(String keycloakVersion)
+ throws AppModelResolverException {
+ // initialize Quarkus application model resolver
+ BootstrapAppModelResolver appModelResolver = new BootstrapAppModelResolver(getMavenArtifactResolver());
+
+ // configure server dependencies
+ WorkspaceModule module = createWorkspaceModule(keycloakVersion);
+
+ // resolve Keycloak server Quarkus application model
+ return appModelResolver.resolveModel(module);
+ }
+
+ private WorkspaceModule createWorkspaceModule(String keycloakVersion) {
+ Path moduleDir = createModuleDir();
+
+ WorkspaceModule.Mutable builder = WorkspaceModule.builder()
+ .setModuleId(WorkspaceModuleId.of("io.playground", "keycloak-app", "1"))
+ .setModuleDir(moduleDir)
+ .setBuildDir(moduleDir)
+ .addDependencyConstraint(
+ Dependency.pomImport("org.keycloak", "keycloak-quarkus-parent", keycloakVersion))
+ .addDependency(DependencyBuilder.newInstance()
+ .setGroupId("org.keycloak")
+ .setArtifactId("keycloak-quarkus-server-app")
+ .setVersion(keycloakVersion)
+ .addExclusion("org.jboss.logmanager", "log4j-jboss-logmanager")
+ .addExclusion("org.keycloak", "keycloak-crypto-fips1402") //TODO: enable fips
+ .build());
+
+ for (Dependency dependency : dependencies) {
+ builder.addDependency(dependency);
+ }
+
+ return builder.build();
+ }
+
+ private static Path createModuleDir() {
+ Path moduleDir;
+
+ try {
+ moduleDir = Files.createTempDirectory("kc-embedded");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return moduleDir;
+ }
+
+ MavenArtifactResolver getMavenArtifactResolver() throws BootstrapMavenException {
+ return MavenArtifactResolver.builder()
+ .setWorkspaceDiscovery(true)
+ .setOffline(false)
+ .build();
+ }
+
+ private boolean isRunning() {
+ return application != null;
+ }
+
+ private void closeApplication() {
+ if (application != null) {
+ ClassLoader old = Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader(application.getClassLoader());
+ try {
+ application.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ Thread.currentThread().setContextClassLoader(old);
+ }
+ }
+
+ QuarkusConfigFactory.setConfig(null);
+ ClassLoader old = Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
+
+ try {
+ ConfigProviderResolver cpr = ConfigProviderResolver.instance();
+ cpr.releaseConfig(cpr.getConfig());
+ } catch (Throwable ignored) {
+ // just means no config was installed, which is fine
+ } finally {
+ Thread.currentThread().setContextClassLoader(old);
+ }
+
+ application = null;
+ }
+}
diff --git a/testsuite/integration-arquillian/HOW-TO-RUN.md b/testsuite/integration-arquillian/HOW-TO-RUN.md
index f179d109e0..715282573b 100644
--- a/testsuite/integration-arquillian/HOW-TO-RUN.md
+++ b/testsuite/integration-arquillian/HOW-TO-RUN.md
@@ -44,6 +44,23 @@ This can be achieved by add the `auth-server-quarkus` profile when running the t
Unlike the "development" setup described above, this requires re-build the whole distribution
after doing any change in the code.
+### Running tests using an embedded server
+
+For test driven development, it is possible to run the Keycloak server deployed on real Quarkus server.
+This can be achieved by add the `auth-server-quarkus-embedded` profile when running the testsuite.
+
+ mvn -f testsuite/integration-arquillian/pom.xml -Pauth-server-quarkus-embedded clean install -Dtest=LoginTest
+
+After running this command, you should also be able to run tests from your IDE. For that, make sure you have the `auth-server-quarkus-embedded` profile enabled.
+
+When running in embedded mode, the `build` phase happens every time the server is started, and it is based on the same configuration used during a full-distribution test run(e.g.: `auth-server-quarkus` profile is active).
+
+There are a few limitations when running tests. The well-known limitations are:
+
+* FIPS tests not working
+* Deploying script providers not working. Probably any test deploying JAR files.
+* Re-starting the server during a test execution is taking too much metaspace. Need more investigation.
+
## Debugging - tips & tricks
### Arquillian debugging
@@ -465,7 +482,6 @@ This is temporary and database configuration should be more integrated with the
Activate the following profiles:
-* `quarkus`
* `auth-server-cluster-quarkus`
Then run any cluster test as usual.
diff --git a/testsuite/integration-arquillian/tests/base/pom.xml b/testsuite/integration-arquillian/tests/base/pom.xml
index 160555f044..3ca796bffa 100644
--- a/testsuite/integration-arquillian/tests/base/pom.xml
+++ b/testsuite/integration-arquillian/tests/base/pom.xml
@@ -176,6 +176,19 @@
infinispan-server-hotrod
${infinispan.version}
+
+
+
+ org.keycloak
+ keycloak-quarkus-integration-tests
+ ${project.version}
+
+
+ *
+ *
+
+
+
@@ -1056,6 +1069,51 @@
+
+ auth-server-quarkus-embedded
+
+ 1024m
+ 1024m
+ 512m
+ 512m
+
+
+
+ org.keycloak
+ keycloak-quarkus-integration-tests
+ ${project.version}
+
+
+
+
+ org.keycloak
+ keycloak-crypto-fips1402
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+
+
+ io.quarkus
+ quarkus-junit5-internal
+
+
+
+
+ org.jboss.logmanager
+ log4j-jboss-logmanager
+ 1.3.0.Final
+
+
+ net.bytebuddy
+ byte-buddy
+ 1.12.18
+
+
+
+
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/AbstractQuarkusDeployableContainer.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/AbstractQuarkusDeployableContainer.java
new file mode 100644
index 0000000000..b537e4e959
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/AbstractQuarkusDeployableContainer.java
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2022 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.testsuite.arquillian.containers;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Supplier;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import org.apache.commons.lang3.SystemUtils;
+import org.jboss.arquillian.container.spi.client.container.DeployableContainer;
+import org.jboss.arquillian.container.spi.client.container.DeploymentException;
+import org.jboss.arquillian.container.spi.client.container.LifecycleException;
+import org.jboss.arquillian.container.spi.client.protocol.ProtocolDescription;
+import org.jboss.arquillian.container.spi.client.protocol.metadata.ProtocolMetaData;
+import org.jboss.arquillian.core.api.Instance;
+import org.jboss.arquillian.core.api.annotation.Inject;
+import org.jboss.logging.Logger;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.exporter.ZipExporter;
+import org.jboss.shrinkwrap.descriptor.api.Descriptor;
+import org.keycloak.common.crypto.FipsMode;
+import org.keycloak.testsuite.arquillian.SuiteContext;
+import org.keycloak.testsuite.model.StoreProvider;
+
+public abstract class AbstractQuarkusDeployableContainer implements DeployableContainer {
+
+ private static final Logger log = Logger.getLogger(AbstractQuarkusDeployableContainer.class);
+
+ protected static AtomicBoolean restart = new AtomicBoolean();
+
+ @Inject
+ protected Instance suiteContext;
+
+ protected KeycloakQuarkusConfiguration configuration;
+ protected List additionalBuildArgs = Collections.emptyList();
+
+ @Override
+ public Class getConfigurationClass() {
+ return KeycloakQuarkusConfiguration.class;
+ }
+
+ @Override
+ public void setup(KeycloakQuarkusConfiguration configuration) {
+ this.configuration = configuration;
+ }
+
+ @Override
+ public ProtocolMetaData deploy(Archive> archive) throws DeploymentException {
+ try {
+ deployArchiveToServer(archive);
+ restartServer();
+ } catch (Exception e) {
+ throw new DeploymentException(e.getMessage(),e);
+ }
+
+ return new ProtocolMetaData();
+ }
+
+ @Override
+ public void undeploy(Archive> archive) throws DeploymentException {
+ File wrkDir = configuration.getProvidersPath().resolve("providers").toFile();
+ try {
+ if (isWindows()) {
+ // stop before updating providers to avoid file locking issues on Windows
+ stop();
+ }
+ Files.deleteIfExists(wrkDir.toPath().resolve(archive.getName()));
+ restartServer();
+ } catch (Exception e) {
+ throw new DeploymentException(e.getMessage(),e);
+ }
+ }
+
+ @Override
+ public ProtocolDescription getDefaultProtocol() {
+ return null;
+ }
+
+ @Override
+ public void deploy(Descriptor descriptor) throws DeploymentException {
+
+ }
+
+ @Override
+ public void undeploy(Descriptor descriptor) throws DeploymentException {
+
+ }
+
+ public void restartServer() throws Exception {
+ stop();
+ start();
+ }
+
+ protected List getArgs() {
+ return getArgs(new HashMap<>());
+ }
+
+ protected List getArgs(Map env) {
+ List commands = new ArrayList<>();
+
+ commands.add("-v");
+ commands.add("start");
+ commands.add("--http-enabled=true");
+
+ if (Boolean.parseBoolean(System.getProperty("auth.server.debug", "false"))) {
+ commands.add("--debug");
+
+ String debugPort = configuration.getDebugPort() > 0 ? Integer.toString(configuration.getDebugPort()) : System.getProperty("auth.server.debug.port", "5005");
+ env.put("DEBUG_PORT", debugPort);
+
+ String debugSuspend = System.getProperty("auth.server.debug.suspend");
+ if (debugSuspend != null) {
+ env.put("DEBUG_SUSPEND", debugSuspend);
+ }
+ }
+
+ commands.add("--http-port=" + configuration.getBindHttpPort());
+ commands.add("--https-port=" + configuration.getBindHttpsPort());
+
+ if (configuration.getRoute() != null) {
+ commands.add("-Djboss.node.name=" + configuration.getRoute());
+ }
+
+ if (System.getProperty("auth.server.quarkus.log-level") != null) {
+ commands.add("--log-level=" + System.getProperty("auth.server.quarkus.log-level"));
+ }
+
+ commands.addAll(getAdditionalBuildArgs());
+
+ commands = configureArgs(commands);
+
+ final StoreProvider storeProvider = StoreProvider.getCurrentProvider();
+ final Supplier shouldSetUpDb = () -> !restart.get() && !storeProvider.equals(StoreProvider.DEFAULT);
+ final Supplier getClusterConfig = () -> System.getProperty("auth.server.quarkus.cluster.config", "local");
+
+ log.debugf("FIPS Mode: %s", configuration.getFipsMode());
+
+ // only run build during first execution of the server (if the DB is specified), restarts or when running cluster tests
+ if (restart.get() || shouldSetUpDb.get() || "ha".equals(getClusterConfig.get()) || configuration.getFipsMode() != FipsMode.disabled) {
+ commands.removeIf("--optimized"::equals);
+ commands.add("--http-relative-path=/auth");
+
+ if (!storeProvider.isMapStore()) {
+ String cacheMode = getClusterConfig.get();
+
+ if ("local".equals(cacheMode)) {
+ commands.add("--cache=local");
+ } else {
+ commands.add("--cache-config-file=cluster-" + cacheMode + ".xml");
+ }
+ }
+
+ if (configuration.getFipsMode() != FipsMode.disabled) {
+ addFipsOptions(commands);
+ }
+ }
+
+ addStorageOptions(storeProvider, commands);
+
+ return commands;
+ }
+
+ protected List configureArgs(List commands) {
+ return commands;
+ }
+
+ private void deployArchiveToServer(Archive> archive) throws IOException, LifecycleException {
+ if (isWindows()) {
+ // stop before updating providers to avoid file locking issues on Windows
+ stop();
+ }
+ File providersDir = configuration.getProvidersPath().resolve("providers").toFile();
+ InputStream zipStream = archive.as(ZipExporter.class).exportAsInputStream();
+ Files.copy(zipStream, providersDir.toPath().resolve(archive.getName()), StandardCopyOption.REPLACE_EXISTING);
+ }
+
+ protected static boolean isWindows() {
+ return SystemUtils.IS_OS_WINDOWS;
+ }
+
+ public List getAdditionalBuildArgs() {
+ return additionalBuildArgs;
+ }
+
+ public void setAdditionalBuildArgs(List newArgs) {
+ additionalBuildArgs = newArgs;
+ }
+
+ public void resetConfiguration() {
+ additionalBuildArgs = Collections.emptyList();
+ }
+
+ protected void waitForReadiness() throws MalformedURLException, LifecycleException {
+ SuiteContext suiteContext = this.suiteContext.get();
+ //TODO: not sure if the best endpoint but it makes sure that everything is properly initialized. Once we have
+ // support for MP Health this should change
+ URL contextRoot = new URL(getBaseUrl(suiteContext) + "/auth/realms/master/");
+ HttpURLConnection connection;
+ long startTime = System.currentTimeMillis();
+
+ while (true) {
+ if (System.currentTimeMillis() - startTime > getStartTimeout()) {
+ stop();
+ throw new IllegalStateException("Timeout [" + getStartTimeout() + "] while waiting for Quarkus server");
+ }
+
+ try {
+ // wait before checking for opening a new connection
+ Thread.sleep(1000);
+ if ("https".equals(contextRoot.getProtocol())) {
+ HttpsURLConnection httpsConnection = (HttpsURLConnection) (connection = (HttpURLConnection) contextRoot.openConnection());
+ httpsConnection.setSSLSocketFactory(createInsecureSslSocketFactory());
+ httpsConnection.setHostnameVerifier(createInsecureHostnameVerifier());
+ } else {
+ connection = (HttpURLConnection) contextRoot.openConnection();
+ }
+
+ connection.setReadTimeout((int) getStartTimeout());
+ connection.setConnectTimeout((int) getStartTimeout());
+ connection.connect();
+
+ if (connection.getResponseCode() == 200) {
+ break;
+ }
+
+ connection.disconnect();
+ } catch (Exception ignore) {
+ }
+ }
+
+ log.infof("Keycloak is ready at %s", contextRoot);
+ }
+
+ private URL getBaseUrl(SuiteContext suiteContext) throws MalformedURLException {
+ URL baseUrl = suiteContext.getAuthServerInfo().getContextRoot();
+
+ // might be running behind a load balancer
+ if ("https".equals(baseUrl.getProtocol())) {
+ baseUrl = new URL(baseUrl.toString().replace(String.valueOf(baseUrl.getPort()), String.valueOf(configuration.getBindHttpsPort())));
+ } else {
+ baseUrl = new URL(baseUrl.toString().replace(String.valueOf(baseUrl.getPort()), String.valueOf(configuration.getBindHttpPort())));
+ }
+ return baseUrl;
+ }
+
+ private HostnameVerifier createInsecureHostnameVerifier() {
+ return new HostnameVerifier() {
+ @Override
+ public boolean verify(String s, SSLSession sslSession) {
+ return true;
+ }
+ };
+ }
+
+ private SSLSocketFactory createInsecureSslSocketFactory() throws IOException {
+ TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
+ public void checkClientTrusted(final X509Certificate[] chain, final String authType) {
+ }
+
+ public void checkServerTrusted(final X509Certificate[] chain, final String authType) {
+ }
+
+ public X509Certificate[] getAcceptedIssuers() {
+ return null;
+ }
+ }};
+
+ SSLContext sslContext;
+ SSLSocketFactory socketFactory;
+
+ try {
+ sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
+ socketFactory = sslContext.getSocketFactory();
+ } catch (NoSuchAlgorithmException | KeyManagementException e) {
+ throw new IOException("Can't create unsecure trust manager");
+ }
+ return socketFactory;
+ }
+
+ private long getStartTimeout() {
+ return TimeUnit.SECONDS.toMillis(configuration.getStartupTimeoutInSeconds());
+ }
+
+ private void addStorageOptions(StoreProvider storeProvider, List commands) {
+ log.debugf("Store '%s' is used.", storeProvider.name());
+ storeProvider.addStoreOptions(commands);
+ }
+
+ private void addFipsOptions(List commands) {
+ commands.add("--fips-mode=" + configuration.getFipsMode().toString());
+
+ log.debugf("Keystore file: %s, keystore type: %s, truststore file: %s, truststore type: %s",
+ configuration.getKeystoreFile(), configuration.getKeystoreType(),
+ configuration.getTruststoreFile(), configuration.getTruststoreType());
+ commands.add("--https-key-store-file=" + configuration.getKeystoreFile());
+ commands.add("--https-key-store-type=" + configuration.getKeystoreType());
+ commands.add("--https-key-store-password=" + configuration.getKeystorePassword());
+ commands.add("--https-trust-store-file=" + configuration.getTruststoreFile());
+ commands.add("--https-trust-store-type=" + configuration.getTruststoreType());
+ commands.add("--https-trust-store-password=" + configuration.getTruststorePassword());
+ commands.add("--spi-truststore-file-file=" + configuration.getTruststoreFile());
+ commands.add("--spi-truststore-file-password=" + configuration.getTruststorePassword());
+ commands.add("--spi-truststore-file-type=" + configuration.getTruststoreType());
+
+ // BCFIPS approved mode requires passwords of at least 112 bits (14 characters) to be used. To bypass this, we use this by default
+ // as testsuite uses shorter passwords everywhere
+ if (FipsMode.strict == configuration.getFipsMode()) {
+ commands.add("--spi-password-hashing-pbkdf2-max-padding-length=14");
+ commands.add("--spi-password-hashing-pbkdf2-sha256-max-padding-length=14");
+ commands.add("--spi-password-hashing-pbkdf2-sha512-max-padding-length=14");
+ }
+
+ commands.add("--log-level=INFO,org.keycloak.common.crypto:TRACE,org.keycloak.crypto:TRACE,org.keycloak.truststore:TRACE");
+
+ configuration.appendJavaOpts("-Djava.security.properties=" + System.getProperty("auth.server.java.security.file"));
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/KeycloakQuarkusEmbeddedDeployableContainer.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/KeycloakQuarkusEmbeddedDeployableContainer.java
new file mode 100644
index 0000000000..9d0ff52b7d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/KeycloakQuarkusEmbeddedDeployableContainer.java
@@ -0,0 +1,56 @@
+package org.keycloak.testsuite.arquillian.containers;
+
+import java.util.List;
+import org.jboss.arquillian.container.spi.client.container.LifecycleException;
+import org.keycloak.Keycloak;
+import org.keycloak.common.Version;
+
+/**
+ * @author mhajas
+ */
+public class KeycloakQuarkusEmbeddedDeployableContainer extends AbstractQuarkusDeployableContainer {
+
+ private static final String KEYCLOAK_VERSION = Version.VERSION;
+
+ private Keycloak keycloak;
+
+ @Override
+ public void start() throws LifecycleException {
+ try {
+ keycloak = configure().start(getArgs());
+ waitForReadiness();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void stop() throws LifecycleException {
+ if (keycloak != null) {
+ try {
+ keycloak.stop();
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to stop the server", e);
+ } finally {
+ keycloak = null;
+ }
+ }
+ }
+
+ private Keycloak.Builder configure() {
+ return Keycloak.builder()
+ .setHomeDir(configuration.getProvidersPath())
+ .setVersion(KEYCLOAK_VERSION)
+ .addDependency("org.keycloak.testsuite", "integration-arquillian-testsuite-providers", KEYCLOAK_VERSION)
+ .addDependency("org.keycloak.testsuite", "integration-arquillian-testsuite-providers", KEYCLOAK_VERSION)
+ .addDependency("org.keycloak.testsuite", "integration-arquillian-tests-base", KEYCLOAK_VERSION)
+ .addDependency("org.keycloak.testsuite", "integration-arquillian-tests-base", KEYCLOAK_VERSION, "tests");
+ }
+
+ @Override
+ protected List configureArgs(List args) {
+ System.setProperty("quarkus.http.test-port", String.valueOf(configuration.getBindHttpPort()));
+ System.setProperty("quarkus.http.test-ssl-port", String.valueOf(configuration.getBindHttpsPort()));
+ return args;
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/KeycloakQuarkusServerDeployableContainer.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/KeycloakQuarkusServerDeployableContainer.java
index 703033e6eb..055744c3aa 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/KeycloakQuarkusServerDeployableContainer.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/KeycloakQuarkusServerDeployableContainer.java
@@ -1,17 +1,7 @@
package org.keycloak.testsuite.arquillian.containers;
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.FileVisitResult;
@@ -20,68 +10,32 @@ import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
-import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes;
-import java.security.KeyManagementException;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.X509Certificate;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.apache.commons.exec.StreamPumper;
-import org.apache.commons.lang3.SystemUtils;
-import org.jboss.arquillian.container.spi.client.container.DeployableContainer;
-import org.jboss.arquillian.container.spi.client.container.DeploymentException;
import org.jboss.arquillian.container.spi.client.container.LifecycleException;
-import org.jboss.arquillian.container.spi.client.protocol.ProtocolDescription;
-import org.jboss.arquillian.container.spi.client.protocol.metadata.ProtocolMetaData;
-import org.jboss.arquillian.core.api.Instance;
-import org.jboss.arquillian.core.api.annotation.Inject;
import org.jboss.logging.Logger;
-import org.jboss.shrinkwrap.api.Archive;
-import org.jboss.shrinkwrap.api.exporter.ZipExporter;
-import org.jboss.shrinkwrap.descriptor.api.Descriptor;
-import org.keycloak.common.crypto.FipsMode;
-import org.keycloak.testsuite.arquillian.SuiteContext;
import org.keycloak.testsuite.model.StoreProvider;
/**
* @author mhajas
*/
-public class KeycloakQuarkusServerDeployableContainer implements DeployableContainer {
+public class KeycloakQuarkusServerDeployableContainer extends AbstractQuarkusDeployableContainer {
private static final int DEFAULT_SHUTDOWN_TIMEOUT_SECONDS = 10;
private static final Logger log = Logger.getLogger(KeycloakQuarkusServerDeployableContainer.class);
- private KeycloakQuarkusConfiguration configuration;
private Process container;
- private static AtomicBoolean restart = new AtomicBoolean();
private Thread stdoutForwarderThread;
- @Inject
- private Instance suiteContext;
-
- private List additionalBuildArgs = Collections.emptyList();
-
- @Override
- public Class getConfigurationClass() {
- return KeycloakQuarkusConfiguration.class;
- }
-
- @Override
- public void setup(KeycloakQuarkusConfiguration configuration) {
- this.configuration = configuration;
- }
-
@Override
public void start() throws LifecycleException {
try {
@@ -109,50 +63,6 @@ public class KeycloakQuarkusServerDeployableContainer implements DeployableConta
}
}
- @Override
- public ProtocolDescription getDefaultProtocol() {
- return null;
- }
-
- @Override
- public ProtocolMetaData deploy(Archive> archive) throws DeploymentException {
- log.infof("Trying to deploy: " + archive.getName());
-
- try {
- deployArchiveToServer(archive);
- restartServer();
- } catch (Exception e) {
- throw new DeploymentException(e.getMessage(),e);
- }
-
- return new ProtocolMetaData();
- }
-
- @Override
- public void undeploy(Archive> archive) throws DeploymentException {
- File wrkDir = configuration.getProvidersPath().resolve("providers").toFile();
- try {
- if (isWindows()) {
- // stop before updating providers to avoid file locking issues on Windows
- stop();
- }
- Files.deleteIfExists(wrkDir.toPath().resolve(archive.getName()));
- restartServer();
- } catch (Exception e) {
- throw new DeploymentException(e.getMessage(),e);
- }
- }
-
- @Override
- public void deploy(Descriptor descriptor) throws DeploymentException {
-
- }
-
- @Override
- public void undeploy(Descriptor descriptor) throws DeploymentException {
-
- }
-
private void importRealm() throws IOException, URISyntaxException {
if (suiteContext.get().isAuthServerMigrationEnabled() && configuration.getImportFile() != null) {
final String importFileName = configuration.getImportFile();
@@ -201,224 +111,28 @@ public class KeycloakQuarkusServerDeployableContainer implements DeployableConta
return builder.start();
}
- private ProcessBuilder getProcessBuilder() {
- List commands = new ArrayList<>();
- Map env = new HashMap<>();
+ @Override
+ protected List configureArgs(List args) {
+ List commands = new ArrayList<>(args);
- commands.add(getCommand());
- commands.add("-v");
- commands.add("start");
+ commands.add(0, getCommand());
commands.add("--optimized");
- commands.add("--http-enabled=true");
-
- if (Boolean.parseBoolean(System.getProperty("auth.server.debug", "false"))) {
- commands.add("--debug");
-
- String debugPort = configuration.getDebugPort() > 0 ? Integer.toString(configuration.getDebugPort()) : System.getProperty("auth.server.debug.port", "5005");
- env.put("DEBUG_PORT", debugPort);
-
- String debugSuspend = System.getProperty("auth.server.debug.suspend");
- if (debugSuspend != null) {
- env.put("DEBUG_SUSPEND", debugSuspend);
- }
- }
-
- commands.add("--http-port=" + configuration.getBindHttpPort());
- commands.add("--https-port=" + configuration.getBindHttpsPort());
-
- if (configuration.getRoute() != null) {
- commands.add("-Djboss.node.name=" + configuration.getRoute());
- }
-
- final StoreProvider storeProvider = StoreProvider.getCurrentProvider();
-
- final Supplier shouldSetUpDb = () -> !restart.get() && !storeProvider.equals(StoreProvider.DEFAULT);
- final Supplier getClusterConfig = () -> System.getProperty("auth.server.quarkus.cluster.config", "local");
-
- log.debugf("FIPS Mode: %s", configuration.getFipsMode());
-
- // only run build during first execution of the server (if the DB is specified), restarts or when running cluster tests
- if (restart.get() || shouldSetUpDb.get() || "ha".equals(getClusterConfig.get()) || configuration.getFipsMode() != FipsMode.disabled) {
- commands.removeIf("--optimized"::equals);
- commands.add("--http-relative-path=/auth");
-
- if (!storeProvider.isMapStore()) {
- String cacheMode = getClusterConfig.get();
-
- if ("local".equals(cacheMode)) {
- commands.add("--cache=local");
- } else {
- commands.add("--cache-config-file=cluster-" + cacheMode + ".xml");
- }
- }
-
- if (configuration.getFipsMode() != FipsMode.disabled) {
- addFipsOptions(commands);
- }
- }
-
- addStorageOptions(storeProvider, commands);
- if (System.getProperty("auth.server.quarkus.log-level") != null) {
- commands.add("--log-level=" + System.getProperty("auth.server.quarkus.log-level"));
- }
-
- commands.addAll(getAdditionalBuildArgs());
log.debugf("Quarkus parameters: %s", commands);
- String[] processCommands = commands.toArray(new String[0]);
+ return commands;
+ }
+ private ProcessBuilder getProcessBuilder() {
+ Map env = new HashMap<>();
+ String[] processCommands = getArgs(env).toArray(new String[0]);
ProcessBuilder pb = new ProcessBuilder(processCommands);
+
pb.environment().putAll(env);
return pb;
}
- private void addStorageOptions(StoreProvider storeProvider, List commands) {
- log.debugf("Store '%s' is used.", storeProvider.name());
- storeProvider.addStoreOptions(commands);
- }
-
- private void addFipsOptions(List commands) {
- commands.add("--fips-mode=" + configuration.getFipsMode().toString());
-
- log.debugf("Keystore file: %s, keystore type: %s, truststore file: %s, truststore type: %s",
- configuration.getKeystoreFile(), configuration.getKeystoreType(),
- configuration.getTruststoreFile(), configuration.getTruststoreType());
- commands.add("--https-key-store-file=" + configuration.getKeystoreFile());
- commands.add("--https-key-store-type=" + configuration.getKeystoreType());
- commands.add("--https-key-store-password=" + configuration.getKeystorePassword());
- commands.add("--https-trust-store-file=" + configuration.getTruststoreFile());
- commands.add("--https-trust-store-type=" + configuration.getTruststoreType());
- commands.add("--https-trust-store-password=" + configuration.getTruststorePassword());
- commands.add("--spi-truststore-file-file=" + configuration.getTruststoreFile());
- commands.add("--spi-truststore-file-password=" + configuration.getTruststorePassword());
- commands.add("--spi-truststore-file-type=" + configuration.getTruststoreType());
-
- // BCFIPS approved mode requires passwords of at least 112 bits (14 characters) to be used. To bypass this, we use this by default
- // as testsuite uses shorter passwords everywhere
- if (FipsMode.strict == configuration.getFipsMode()) {
- commands.add("--spi-password-hashing-pbkdf2-max-padding-length=14");
- commands.add("--spi-password-hashing-pbkdf2-sha256-max-padding-length=14");
- commands.add("--spi-password-hashing-pbkdf2-sha512-max-padding-length=14");
- }
-
- commands.add("--log-level=INFO,org.keycloak.common.crypto:TRACE,org.keycloak.crypto:TRACE,org.keycloak.truststore:TRACE");
-
- configuration.appendJavaOpts("-Djava.security.properties=" + System.getProperty("auth.server.java.security.file"));
- }
-
- private void waitForReadiness() throws MalformedURLException, LifecycleException {
- SuiteContext suiteContext = this.suiteContext.get();
- //TODO: not sure if the best endpoint but it makes sure that everything is properly initialized. Once we have
- // support for MP Health this should change
- URL contextRoot = new URL(getBaseUrl(suiteContext) + "/auth/realms/master/");
- HttpURLConnection connection;
- long startTime = System.currentTimeMillis();
-
- while (true) {
- if (System.currentTimeMillis() - startTime > getStartTimeout()) {
- stop();
- throw new IllegalStateException("Timeout [" + getStartTimeout() + "] while waiting for Quarkus server");
- }
-
- try {
- // wait before checking for opening a new connection
- Thread.sleep(1000);
- if ("https".equals(contextRoot.getProtocol())) {
- HttpsURLConnection httpsConnection = (HttpsURLConnection) (connection = (HttpURLConnection) contextRoot.openConnection());
- httpsConnection.setSSLSocketFactory(createInsecureSslSocketFactory());
- httpsConnection.setHostnameVerifier(createInsecureHostnameVerifier());
- } else {
- connection = (HttpURLConnection) contextRoot.openConnection();
- }
-
- connection.setReadTimeout((int) getStartTimeout());
- connection.setConnectTimeout((int) getStartTimeout());
- connection.connect();
-
- if (connection.getResponseCode() == 200) {
- break;
- }
-
- connection.disconnect();
- } catch (Exception ignore) {
- }
- }
-
- log.infof("Keycloak is ready at %s", contextRoot);
- }
-
- private URL getBaseUrl(SuiteContext suiteContext) throws MalformedURLException {
- URL baseUrl = suiteContext.getAuthServerInfo().getContextRoot();
-
- // might be running behind a load balancer
- if ("https".equals(baseUrl.getProtocol())) {
- baseUrl = new URL(baseUrl.toString().replace(String.valueOf(baseUrl.getPort()), String.valueOf(configuration.getBindHttpsPort())));
- } else {
- baseUrl = new URL(baseUrl.toString().replace(String.valueOf(baseUrl.getPort()), String.valueOf(configuration.getBindHttpPort())));
- }
- return baseUrl;
- }
-
- private HostnameVerifier createInsecureHostnameVerifier() {
- return new HostnameVerifier() {
- @Override
- public boolean verify(String s, SSLSession sslSession) {
- return true;
- }
- };
- }
-
- private SSLSocketFactory createInsecureSslSocketFactory() throws IOException {
- TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
- public void checkClientTrusted(final X509Certificate[] chain, final String authType) {
- }
-
- public void checkServerTrusted(final X509Certificate[] chain, final String authType) {
- }
-
- public X509Certificate[] getAcceptedIssuers() {
- return null;
- }
- }};
-
- SSLContext sslContext;
- SSLSocketFactory socketFactory;
-
- try {
- sslContext = SSLContext.getInstance("TLS");
- sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
- socketFactory = sslContext.getSocketFactory();
- } catch (NoSuchAlgorithmException | KeyManagementException e) {
- throw new IOException("Can't create unsecure trust manager");
- }
- return socketFactory;
- }
-
- private long getStartTimeout() {
- return TimeUnit.SECONDS.toMillis(configuration.getStartupTimeoutInSeconds());
- }
-
- public void resetConfiguration() {
- additionalBuildArgs = Collections.emptyList();
- }
-
- private void deployArchiveToServer(Archive> archive) throws IOException, LifecycleException {
- if (isWindows()) {
- // stop before updating providers to avoid file locking issues on Windows
- stop();
- }
- File providersDir = configuration.getProvidersPath().resolve("providers").toFile();
- InputStream zipStream = archive.as(ZipExporter.class).exportAsInputStream();
- Files.copy(zipStream, providersDir.toPath().resolve(archive.getName()), StandardCopyOption.REPLACE_EXISTING);
- }
-
- public void restartServer() throws Exception {
- stop();
- start();
- }
-
private String getCommand() {
if (isWindows()) {
return configuration.getProvidersPath().resolve("bin").resolve("kc.bat").toString();
@@ -426,14 +140,6 @@ public class KeycloakQuarkusServerDeployableContainer implements DeployableConta
return "./kc.sh";
}
- public List getAdditionalBuildArgs() {
- return additionalBuildArgs;
- }
-
- public void setAdditionalBuildArgs(List newArgs) {
- additionalBuildArgs = newArgs;
- }
-
private void destroyDescendantsOnWindows(Process parent, boolean force) {
if (!isWindows()) {
return;
@@ -467,10 +173,6 @@ public class KeycloakQuarkusServerDeployableContainer implements DeployableConta
}
}
- private static boolean isWindows() {
- return SystemUtils.IS_OS_WINDOWS;
- }
-
public static void deleteDirectory(final Path directory) throws IOException {
if (Files.isDirectory(directory, new LinkOption[0])) {
Files.walkFileTree(directory, new SimpleFileVisitor() {
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/MultipleContainersExtension.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/MultipleContainersExtension.java
index 3d336be347..b59e7ba4cf 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/MultipleContainersExtension.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/MultipleContainersExtension.java
@@ -44,6 +44,7 @@ public class MultipleContainersExtension implements LoadableExtension {
logger.info("Multiple containers extension registering.");
builder.service(DeployableContainer.class, KeycloakQuarkusServerDeployableContainer.class)
+ .service(DeployableContainer.class, KeycloakQuarkusEmbeddedDeployableContainer.class)
.service(DeployableContainer.class, InfinispanServerDeployableContainer.class);
builder.context(ContainerContextImpl.class).context(DeploymentContextImpl.class);
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/model/StoreProvider.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/model/StoreProvider.java
index 09107e681c..5289289d62 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/model/StoreProvider.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/model/StoreProvider.java
@@ -38,7 +38,7 @@ public enum StoreProvider {
public void addStoreOptions(List commands) {
commands.add("--storage=" + getAlias());
getDbVendor().ifPresent(vendor -> commands.add("--db=" + vendor));
- commands.add("--db-url='" + System.getProperty("keycloak.map.storage.connectionsJpa.url") + "'");
+ commands.add("--db-url=" + System.getProperty("keycloak.map.storage.connectionsJpa.url"));
commands.add("--db-username=" + System.getProperty("keycloak.map.storage.connectionsJpa.user"));
commands.add("--db-password=" + System.getProperty("keycloak.map.storage.connectionsJpa.password"));
}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/ContainerAssume.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/ContainerAssume.java
index 0cd0269263..34d73e386f 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/ContainerAssume.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/ContainerAssume.java
@@ -57,11 +57,11 @@ public class ContainerAssume {
public static void assumeNotAuthServerQuarkus() {
Assume.assumeFalse("Doesn't work on auth-server-quarkus",
- AuthServerTestEnricher.AUTH_SERVER_CONTAINER.equals("auth-server-quarkus"));
+ AuthServerTestEnricher.AUTH_SERVER_CONTAINER.startsWith("auth-server-quarkus"));
}
public static void assumeAuthServerQuarkus() {
Assume.assumeTrue("Only works on auth-server-quarkus",
- AuthServerTestEnricher.AUTH_SERVER_CONTAINER.equals("auth-server-quarkus"));
+ AuthServerTestEnricher.AUTH_SERVER_CONTAINER.startsWith("auth-server-quarkus"));
}
}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/SpiProvidersSwitchingUtils.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/SpiProvidersSwitchingUtils.java
index f4980c5dc5..a95f58e821 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/SpiProvidersSwitchingUtils.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/SpiProvidersSwitchingUtils.java
@@ -2,17 +2,12 @@ package org.keycloak.testsuite.util;
import org.jboss.arquillian.container.spi.Container;
import org.jboss.logging.Logger;
-import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
import org.keycloak.testsuite.arquillian.ContainerInfo;
import org.keycloak.testsuite.arquillian.SuiteContext;
import org.keycloak.testsuite.arquillian.annotation.SetDefaultProvider;
-import org.keycloak.testsuite.arquillian.containers.KeycloakQuarkusServerDeployableContainer;
+import org.keycloak.testsuite.arquillian.containers.AbstractQuarkusDeployableContainer;
import org.keycloak.utils.StringUtil;
-import org.wildfly.extras.creaper.core.online.CliException;
-import org.wildfly.extras.creaper.core.online.ModelNodeResult;
-import org.wildfly.extras.creaper.core.online.OnlineManagementClient;
-import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
@@ -58,8 +53,8 @@ public class SpiProvidersSwitchingUtils {
getQuarkusContainer(container).setAdditionalBuildArgs(Collections.emptyList());
}
- private KeycloakQuarkusServerDeployableContainer getQuarkusContainer(Container container) {
- return (KeycloakQuarkusServerDeployableContainer) container.getDeployableContainer();
+ private AbstractQuarkusDeployableContainer getQuarkusContainer(Container container) {
+ return (AbstractQuarkusDeployableContainer) container.getDeployableContainer();
}
/**
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientSearchTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientSearchTest.java
index c01c6bd6c2..6938b7fc1c 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientSearchTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientSearchTest.java
@@ -25,7 +25,7 @@ import org.junit.Before;
import org.junit.Test;
import org.keycloak.models.ClientProvider;
import org.keycloak.representations.idm.ClientRepresentation;
-import org.keycloak.testsuite.arquillian.containers.KeycloakQuarkusServerDeployableContainer;
+import org.keycloak.testsuite.arquillian.containers.AbstractQuarkusDeployableContainer;
import java.util.Arrays;
import java.util.Collections;
@@ -147,7 +147,7 @@ public class ClientSearchTest extends AbstractClientTest {
.toArray(String[]::new);
String s = String.join(",",searchableAttributes);
controller.stop(suiteContext.getAuthServerInfo().getQualifier());
- KeycloakQuarkusServerDeployableContainer container = (KeycloakQuarkusServerDeployableContainer)suiteContext.getAuthServerInfo().getArquillianContainer().getDeployableContainer();
+ AbstractQuarkusDeployableContainer container = (AbstractQuarkusDeployableContainer)suiteContext.getAuthServerInfo().getArquillianContainer().getDeployableContainer();
container.setAdditionalBuildArgs(Collections.singletonList("--spi-client-jpa-searchable-attributes=\""+ s + "\""));
controller.start(suiteContext.getAuthServerInfo().getQualifier());
} else {
@@ -165,7 +165,7 @@ public class ClientSearchTest extends AbstractClientTest {
System.clearProperty(SEARCHABLE_ATTRS_PROP);
controller.start(suiteContext.getAuthServerInfo().getQualifier());
} else if (suiteContext.getAuthServerInfo().isQuarkus()) {
- KeycloakQuarkusServerDeployableContainer container = (KeycloakQuarkusServerDeployableContainer) suiteContext.getAuthServerInfo().getArquillianContainer().getDeployableContainer();
+ AbstractQuarkusDeployableContainer container = (AbstractQuarkusDeployableContainer) suiteContext.getAuthServerInfo().getArquillianContainer().getDeployableContainer();
container.setAdditionalBuildArgs(Collections.emptyList());
container.restartServer();
} else {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/group/GroupSearchTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/group/GroupSearchTest.java
index e349a3b969..28cbb87452 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/group/GroupSearchTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/group/GroupSearchTest.java
@@ -23,11 +23,8 @@ import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.models.GroupProvider;
import org.keycloak.representations.idm.GroupRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
-import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
-import org.keycloak.testsuite.arquillian.containers.KeycloakQuarkusServerDeployableContainer;
+import org.keycloak.testsuite.arquillian.containers.AbstractQuarkusDeployableContainer;
import org.keycloak.testsuite.updaters.Creator;
-import org.wildfly.extras.creaper.core.online.OnlineManagementClient;
-import org.wildfly.extras.creaper.core.online.operations.admin.Administration;
public class GroupSearchTest extends AbstractGroupTest {
@ArquillianResource
@@ -166,7 +163,7 @@ public class GroupSearchTest extends AbstractGroupTest {
.toArray(String[]::new);
String s = String.join(",", searchableAttributes);
controller.stop(suiteContext.getAuthServerInfo().getQualifier());
- KeycloakQuarkusServerDeployableContainer container = (KeycloakQuarkusServerDeployableContainer) suiteContext.getAuthServerInfo().getArquillianContainer().getDeployableContainer();
+ AbstractQuarkusDeployableContainer container = (AbstractQuarkusDeployableContainer) suiteContext.getAuthServerInfo().getArquillianContainer().getDeployableContainer();
container.setAdditionalBuildArgs(
Collections.singletonList("--spi-group-jpa-searchable-attributes=\"" + s + "\""));
controller.start(suiteContext.getAuthServerInfo().getQualifier());
@@ -184,7 +181,7 @@ public class GroupSearchTest extends AbstractGroupTest {
System.clearProperty(SEARCHABLE_ATTRS_PROP);
controller.start(suiteContext.getAuthServerInfo().getQualifier());
} else if (suiteContext.getAuthServerInfo().isQuarkus()) {
- KeycloakQuarkusServerDeployableContainer container = (KeycloakQuarkusServerDeployableContainer) suiteContext.getAuthServerInfo().getArquillianContainer().getDeployableContainer();
+ AbstractQuarkusDeployableContainer container = (AbstractQuarkusDeployableContainer) suiteContext.getAuthServerInfo().getArquillianContainer().getDeployableContainer();
container.setAdditionalBuildArgs(Collections.emptyList());
container.restartServer();
} else {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/url/AbstractHostnameTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/url/AbstractHostnameTest.java
index 14eb877bde..dd226242f7 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/url/AbstractHostnameTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/url/AbstractHostnameTest.java
@@ -4,7 +4,7 @@ import org.jboss.arquillian.container.test.api.ContainerController;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.logging.Logger;
import org.keycloak.testsuite.AbstractKeycloakTest;
-import org.keycloak.testsuite.arquillian.containers.KeycloakQuarkusServerDeployableContainer;
+import org.keycloak.testsuite.arquillian.containers.AbstractQuarkusDeployableContainer;
import org.keycloak.testsuite.util.OAuthClient;
import java.net.URI;
@@ -33,7 +33,7 @@ public abstract class AbstractHostnameTest extends AbstractKeycloakTest {
"keycloak.hostname.fixed.alwaysHttps");
controller.start(suiteContext.getAuthServerInfo().getQualifier());
} else if (suiteContext.getAuthServerInfo().isQuarkus()) {
- KeycloakQuarkusServerDeployableContainer container = (KeycloakQuarkusServerDeployableContainer)suiteContext.getAuthServerInfo().getArquillianContainer().getDeployableContainer();
+ AbstractQuarkusDeployableContainer container = (AbstractQuarkusDeployableContainer)suiteContext.getAuthServerInfo().getArquillianContainer().getDeployableContainer();
container.resetConfiguration();
configureDefault(OAuthClient.AUTH_SERVER_ROOT, false, null);
container.restartServer();
@@ -58,7 +58,7 @@ public abstract class AbstractHostnameTest extends AbstractKeycloakTest {
controller.start(suiteContext.getAuthServerInfo().getQualifier());
} else if (suiteContext.getAuthServerInfo().isQuarkus()) {
controller.stop(suiteContext.getAuthServerInfo().getQualifier());
- KeycloakQuarkusServerDeployableContainer container = (KeycloakQuarkusServerDeployableContainer)suiteContext.getAuthServerInfo().getArquillianContainer().getDeployableContainer();
+ AbstractQuarkusDeployableContainer container = (AbstractQuarkusDeployableContainer)suiteContext.getAuthServerInfo().getArquillianContainer().getDeployableContainer();
List additionalArgs = new ArrayList<>();
URI frontendUri = URI.create(frontendUrl);
// enable proxy so that we can check headers are taken into account when building urls
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml
index 7fdefad093..511c148524 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml
@@ -654,6 +654,16 @@
+
+
+ ${auth.server.quarkus.embedded}
+
+ org.keycloak.testsuite.arquillian.containers.KeycloakQuarkusEmbeddedDeployableContainer
+
+ ${auth.server.port.offset}
+
+
+
diff --git a/testsuite/integration-arquillian/tests/pom.xml b/testsuite/integration-arquillian/tests/pom.xml
index 84ad28e446..c17faf67da 100644
--- a/testsuite/integration-arquillian/tests/pom.xml
+++ b/testsuite/integration-arquillian/tests/pom.xml
@@ -92,6 +92,7 @@
false
false
+ false
@@ -569,6 +570,8 @@
${auth.server.remote}
${auth.server.quarkus}
+ ${auth.server.quarkus.embedded}
+ ${auth.server.config.dir}
${adapter.test.props}
${examples.home}
@@ -766,6 +769,20 @@
+
+ auth-server-quarkus-embedded
+
+ quarkus
+ true
+ false
+ false
+ ${auth.server.home}/conf
+ false
+ true
+ true
+
+
+
auth-server-cluster-quarkus