From 3a51b3530d2c5e9011df6c21c7d3748645723e50 Mon Sep 17 00:00:00 2001 From: Tomas Kyjovsky Date: Thu, 4 Feb 2016 20:24:58 +0100 Subject: [PATCH 1/5] KEYCLOAK-1678 Reorganized containers handling. (WIP: adapter-libs installation via CLI doesn't work) --- .../arquillian/AppServerTestEnricher.java | 187 +++++++++ .../arquillian/AuthServerTestEnricher.java | 198 ++++++++++ .../testsuite/arquillian/ContainerInfo.java | 64 ++++ .../arquillian/ContainersTestEnricher.java | 362 ------------------ .../DeploymentArchiveProcessor.java | 8 +- .../arquillian/DeploymentTargetModifier.java | 2 +- .../KeycloakArquillianExtension.java | 3 +- .../testsuite/arquillian/SuiteContext.java | 56 ++- .../testsuite/arquillian/TestContext.java | 70 ++-- .../arquillian/provider/URLProvider.java | 7 +- .../testsuite/auth/page/AuthServer.java | 12 +- .../auth/page/account/AccountManagement.java | 6 +- .../console/page/AdminConsoleRealm.java | 6 +- .../console/page/AdminConsoleRealmsRoot.java | 6 +- .../org/keycloak/testsuite/util/IOUtil.java | 39 +- .../keycloak/testsuite/util/LogChecker.java | 37 ++ .../testsuite/AbstractKeycloakTest.java | 17 +- .../keycloak/testsuite/ContainersTest.java | 34 ++ .../adapter/AbstractAdapterTest.java | 4 +- .../AbstractClientRegistrationTest.java | 3 +- .../client/AdapterInstallationConfigTest.java | 3 +- .../base/src/test/resources/arquillian.xml | 209 +++++----- .../console/page/clients/Client.java | 4 +- .../console/page/clients/Clients.java | 4 - .../page/clients/roles/ClientRoles.java | 4 - .../page/idp/IdentityProviderSettings.java | 4 - .../testsuite/console/page/roles/Roles.java | 4 - .../testsuite/console/page/users/User.java | 5 - .../console/page/users/UserRoleMappings.java | 4 - .../testsuite/console/page/users/Users.java | 5 - .../console/AbstractConsoleTest.java | 1 - .../console/clients/AbstractClientTest.java | 70 ++-- .../console/clients/ClientSettingsTest.java | 4 +- .../console/events/AdminEventsTest.java | 11 +- .../console/roles/AbstractRolesTest.java | 1 + .../console/roles/DefaultRolesTest.java | 7 +- .../console/users/AbstractUserTest.java | 12 +- 37 files changed, 892 insertions(+), 581 deletions(-) create mode 100644 testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AppServerTestEnricher.java create mode 100644 testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AuthServerTestEnricher.java create mode 100644 testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainerInfo.java delete mode 100644 testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainersTestEnricher.java create mode 100644 testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/LogChecker.java create mode 100644 testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/ContainersTest.java diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AppServerTestEnricher.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AppServerTestEnricher.java new file mode 100644 index 0000000000..b47981b790 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AppServerTestEnricher.java @@ -0,0 +1,187 @@ +package org.keycloak.testsuite.arquillian; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import org.jboss.arquillian.container.spi.Container; +import org.jboss.arquillian.container.test.api.ContainerController; +import org.jboss.arquillian.core.api.Instance; +import org.jboss.arquillian.core.api.InstanceProducer; +import org.jboss.arquillian.core.api.annotation.Inject; +import org.jboss.arquillian.core.api.annotation.Observes; +import org.jboss.arquillian.test.spi.annotation.ClassScoped; +import org.jboss.arquillian.test.spi.event.suite.BeforeClass; +import org.jboss.logging.Logger; +import static org.keycloak.testsuite.arquillian.AuthServerTestEnricher.getAuthServerContextRoot; +import static org.keycloak.testsuite.arquillian.AuthServerTestEnricher.getAuthServerQualifier; +import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty; +import org.keycloak.testsuite.arquillian.annotation.AppServerContainer; +import static org.keycloak.testsuite.util.IOUtil.execCommand; +import org.keycloak.testsuite.util.LogChecker; +import static org.keycloak.testsuite.util.WaitUtils.pause; + +/** + * + * @author tkyjovsk + */ +public class AppServerTestEnricher { + + protected final Logger log = Logger.getLogger(this.getClass()); + + @Inject + @ClassScoped + private InstanceProducer testContextProducer; + private TestContext testContext; + + @Inject + private Instance containerController; + + public static String getAppServerQualifier(Class testClass) { + Class annotatedClass = getNearestSuperclassWithAnnotation(testClass, AppServerContainer.class); + + String appServerQ = (annotatedClass == null ? null + : annotatedClass.getAnnotation(AppServerContainer.class).value()); + + return appServerQ; + } + + public static String getAppServerContextRoot() { + return getAppServerContextRoot(0); + } + + public static String getAppServerContextRoot(int clusterPortOffset) { + int httpPort = Integer.parseInt(System.getProperty("app.server.http.port")); // property must be set + int httpsPort = Integer.parseInt(System.getProperty("app.server.https.port")); // property must be set + boolean sslRequired = Boolean.parseBoolean(System.getProperty("app.server.ssl.required")); + + return sslRequired + ? "https://localhost:" + (httpsPort + clusterPortOffset) + : "http://localhost:" + (httpPort + clusterPortOffset); + } + + private ContainerInfo initializeAppServerInfo(Container appServerContainer) { + return initializeAppServerInfo(appServerContainer, 0); + } + + private ContainerInfo initializeAppServerInfo(Container appServerContainer, int clusterPortOffset) { + ContainerInfo appServerInfo = new ContainerInfo(appServerContainer); + try { + + String appServerContextRootStr = isRelative(testContext.getTestClass()) + ? getAuthServerContextRoot(clusterPortOffset) + : getAppServerContextRoot(clusterPortOffset); + + appServerInfo.setContextRoot(new URL(appServerContextRootStr)); + + } catch (MalformedURLException ex) { + throw new IllegalArgumentException(ex); + } + return appServerInfo; + } + + public void updateTestContextWithAppServerInfo(@Observes BeforeClass event) { + testContext = testContextProducer.get(); + String appServerQualifier = getAppServerQualifier(testContext.getTestClass()); + for (Container container : testContext.getSuiteContext().getArquillianContainers()) { + if (container.getContainerConfiguration().getContainerName().equals(appServerQualifier)) { + testContext.setAppServerInfo(initializeAppServerInfo(container)); + } + } + // validate app server + if (appServerQualifier != null && testContext.getAppServerInfo() == null) { + throw new RuntimeException(String.format("No app server container matching '%s' was activated. Check if defined and enabled in arquillian.xml.", appServerQualifier)); + } + log.info("\n\n" + testContext); + } + + public void startAppServer(@Observes(precedence = -1) BeforeClass event) throws MalformedURLException, InterruptedException, IOException { + ContainerController controller = containerController.get(); + if (testContext.isAdapterTest()) { + String appServerQualifier = testContext.getAppServerInfo().getQualifier(); + if (!controller.isStarted(appServerQualifier)) { + controller.start(appServerQualifier); + } + log.info("\n\n\nAPP SERVER STARTED\n\n\n"); + // install adapter libs on JBoss-based container via CLI +// if (testContext.getAppServerInfo().isJBossBased()) { + installAdapterLibsUsingJBossCLIClient(testContext.getAppServerInfo()); +// } + } + } + + private void installAdapterLibsUsingJBossCLIClient(ContainerInfo appServerInfo) throws InterruptedException, IOException { + + log.info("Installing adapter via CLI client"); + + if (!appServerInfo.isJBossBased()) { + throw new IllegalArgumentException("App server must be JBoss-based to run jboss-cli-client."); + } + + String jbossHomePath = appServerInfo.getProperties().get("jbossHome"); + + File bin = new File(jbossHomePath + "/bin"); + String command = "java -jar " + jbossHomePath + "/bin/client/jboss-cli-client.jar"; + String adapterScript = "adapter-install.cli"; + String samlAdapterScript = "adapter-install-saml.cli"; + String managementPort = appServerInfo.getProperties().get("managementPort"); + + String controllerArg = " --controller=localhost:" + managementPort; + if (new File(bin, adapterScript).exists()) { + log.info("Installing adapter to app server via cli script"); + execCommand(command + " --connect --file=" + adapterScript + controllerArg, bin); + } + if (new File(bin, samlAdapterScript).exists()) { + log.info("Installing saml adapter to app server via cli script"); + execCommand(command + " --connect --file=" + samlAdapterScript + controllerArg, bin); + } + if (new File(bin, adapterScript).exists() || new File(bin, samlAdapterScript).exists()) { + log.info("Restarting container"); + execCommand(command + " --connect --command=reload" + controllerArg, bin); + log.info("Container restarted"); + pause(5000); + LogChecker.checkJBossServerLog(jbossHomePath); + } + } + + /** + * + * @param testClass + * @param annotationClass + * @return testClass or the nearest superclass of testClass annotated with + * annotationClass + */ + public static Class getNearestSuperclassWithAnnotation(Class testClass, Class annotationClass) { + return testClass.isAnnotationPresent(annotationClass) ? testClass + : (testClass.getSuperclass().equals(Object.class) ? null // stop recursion + : getNearestSuperclassWithAnnotation(testClass.getSuperclass(), annotationClass)); // continue recursion + } + + public static boolean hasAppServerContainerAnnotation(Class testClass) { + return getNearestSuperclassWithAnnotation(testClass, AppServerContainer.class) != null; + } + + public static boolean isRelative(Class testClass) { + return getAppServerQualifier(testClass).equals(getAuthServerQualifier()); + } + + public static String getAdapterLibsLocationProperty(Class testClass) { + Class annotatedClass = getNearestSuperclassWithAnnotation(testClass, AdapterLibsLocationProperty.class); + return (annotatedClass == null ? null + : annotatedClass.getAnnotation(AdapterLibsLocationProperty.class).value()); + } + + public static boolean isWildflyAppServer(Class testClass) { + return getAppServerQualifier(testClass).contains("wildfly"); + } + + public static boolean isTomcatAppServer(Class testClass) { + return getAppServerQualifier(testClass).contains("tomcat"); + } + + public static boolean isOSGiAppServer(Class testClass) { + String q = getAppServerQualifier(testClass); + return q.contains("karaf") || q.contains("fuse"); + } + +} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AuthServerTestEnricher.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AuthServerTestEnricher.java new file mode 100644 index 0000000000..86176cb820 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AuthServerTestEnricher.java @@ -0,0 +1,198 @@ +/* + * Copyright 2016 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; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; + +import org.jboss.arquillian.container.spi.Container; +import org.jboss.arquillian.container.spi.ContainerRegistry; +import org.jboss.arquillian.container.spi.event.StartContainer; +import org.jboss.arquillian.container.spi.event.StartSuiteContainers; +import org.jboss.arquillian.container.test.api.ContainerController; +import org.jboss.arquillian.core.api.Event; +import org.jboss.arquillian.core.api.Instance; +import org.jboss.arquillian.core.api.InstanceProducer; +import org.jboss.arquillian.core.api.annotation.Inject; +import org.jboss.arquillian.core.api.annotation.Observes; +import org.jboss.arquillian.test.spi.annotation.ClassScoped; +import org.jboss.arquillian.test.spi.annotation.SuiteScoped; +import org.jboss.arquillian.test.spi.event.suite.BeforeClass; +import org.jboss.arquillian.test.spi.event.suite.BeforeSuite; +import org.jboss.logging.Logger; +import org.keycloak.testsuite.util.LogChecker; + +/** + * + * @author tkyjovsk + * @author vramik + */ +public class AuthServerTestEnricher { + + protected final Logger log = Logger.getLogger(this.getClass()); + + @Inject + private Instance containerRegistry; + + @Inject + private Instance containerController; + + @Inject + private Event startContainerEvent; + + private static final String AUTH_SERVER_CONTAINER_PROPERTY = "auth.server.container"; + private static final String AUTH_SERVER_CONTAINER_DEFAULT = "auth-server-undertow"; + + private static final String MIGRATED_AUTH_SERVER_CONTAINER_PROPERTY = "migrated.auth.server.container"; + + @Inject + @SuiteScoped + private InstanceProducer suiteContextProducer; + private SuiteContext suiteContext; + + @Inject + @ClassScoped + private InstanceProducer testContextProducer; + + public static String getAuthServerQualifier() { + return System.getProperty(AUTH_SERVER_CONTAINER_PROPERTY, AUTH_SERVER_CONTAINER_DEFAULT); + } + + public static String getMigratedAuthServerQualifier() { + return System.getProperty(MIGRATED_AUTH_SERVER_CONTAINER_PROPERTY); // == null if migration not enabled + } + + public static String getAuthServerContextRoot() { + return getAuthServerContextRoot(0); + } + + public static String getAuthServerContextRoot(int clusterPortOffset) { + int httpPort = Integer.parseInt(System.getProperty("auth.server.http.port")); // property must be set + int httpsPort = Integer.parseInt(System.getProperty("auth.server.https.port")); // property must be set + boolean sslRequired = Boolean.parseBoolean(System.getProperty("auth.server.ssl.required")); + + return sslRequired + ? "https://localhost:" + (httpsPort + clusterPortOffset) + : "http://localhost:" + (httpPort + clusterPortOffset); + } + + public void initializeSuiteContext(@Observes(precedence = 2) BeforeSuite event) { + suiteContext = new SuiteContext(new ArrayList<>(containerRegistry.get().getContainers())); + + String authServerQualifier = getAuthServerQualifier(); + String migratedAuthServerQualifier = getMigratedAuthServerQualifier(); + + // init authServerInfo and authServerBackendsInfo + if (authServerQualifier.startsWith("auth-server-")) { + + boolean authServerCluster = authServerQualifier.endsWith("-cluster"); + + String authServerType = authServerQualifier.replaceAll("^auth-server-", "").replaceAll("-cluster$", ""); + String authServerFrontend = authServerCluster + ? "auth-server-" + authServerType + "-balancer" // in cluster mode the load-balancer container serves as auth server frontend + : authServerQualifier; // single-node mode + String authServerBackend = "auth-server-" + authServerType + "-backend"; + int backends = 0; + for (Container container : suiteContext.getArquillianContainers()) { + // frontend + if (container.getContainerConfiguration().getContainerName().equals(authServerFrontend)) { + suiteContext.setAuthServerInfo(initializeAuthServerInfo(container)); + } + // backends + if (container.getContainerConfiguration().getContainerName().startsWith(authServerBackend)) { + suiteContext.getAuthServerBackendsInfo().add(initializeAuthServerInfo(container, ++backends)); + } + } + + // validate auth server setup + if (suiteContext.getAuthServerInfo() == null) { + throw new RuntimeException(String.format("No auth server activated. A container matching '%s' needs to be enabled in arquillian.xml.", authServerFrontend)); + } + if (authServerCluster && !suiteContext.getAuthServerBackendsInfo().isEmpty()) { + throw new RuntimeException(String.format("No cluster backend nodes activated. Containers matching '%sN' need to be enabled in arquillian.xml.", authServerBackend)); + } + + } else { + throw new IllegalArgumentException(String.format("Value of %s should start with 'auth-server-' prefix.", AUTH_SERVER_CONTAINER_PROPERTY)); + } + + if (migratedAuthServerQualifier != null) { + // init migratedAuthServerInfo + if (migratedAuthServerQualifier.startsWith("migrated-auth-server-")) { + for (Container container : suiteContext.getArquillianContainers()) { + // migrated auth server + if (container.getContainerConfiguration().getContainerName().equals(migratedAuthServerQualifier)) { + suiteContext.setMigratedAuthServerInfo(initializeAuthServerInfo(container)); + } + } + } else { + throw new IllegalArgumentException(String.format("Value of %s should start with 'migrated-auth-server-' prefix.", MIGRATED_AUTH_SERVER_CONTAINER_PROPERTY)); + } + // validate setup + if (suiteContext.getMigratedAuthServerInfo() == null) { + throw new RuntimeException(String.format("Migration test was enabled but no auth server from which to migrate was activated. " + + "A container matching '%s' needs to be enabled in arquillian.xml.", migratedAuthServerQualifier)); + } + } + + suiteContextProducer.set(suiteContext); + log.info("\n\n" + suiteContext); + } + + public void initializeTestContext(@Observes(precedence = 1) BeforeClass event) { + TestContext testContext = new TestContext(suiteContext, event.getTestClass().getJavaClass()); + testContextProducer.set(testContext); + } + + private ContainerInfo initializeAuthServerInfo(Container authServerContainer) { + return initializeAuthServerInfo(authServerContainer, 0); + } + + private ContainerInfo initializeAuthServerInfo(Container authServerContainer, int clusterPortOffset) { + ContainerInfo authServerInfo = new ContainerInfo(authServerContainer); + try { + authServerInfo.setContextRoot(new URL(getAuthServerContextRoot(clusterPortOffset))); + } catch (MalformedURLException ex) { + throw new IllegalArgumentException(ex); + } + return authServerInfo; + } + + public void startMigratedContainer(@Observes(precedence = 2) StartSuiteContainers event) { + if (suiteContext.isAuthServerMigrationEnabled()) { + log.info("\n\n### Starting keycloak " + System.getProperty("version", "- previous") + " ###\n"); + startContainerEvent.fire(new StartContainer(suiteContext.getMigratedAuthServerInfo().getArquillianContainer())); + } + } + + public void stopMigratedContainer(@Observes(precedence = 1) StartSuiteContainers event) { + if (suiteContext.isAuthServerMigrationEnabled()) { + containerController.get().stop(suiteContext.getAuthServerInfo().getQualifier()); + } + } + + public void checkServerLogs(@Observes(precedence = -1) BeforeSuite event) throws IOException, InterruptedException { + boolean checkLog = System.getProperty("auth.server.log.check", "true").equals("true"); + if (checkLog && suiteContext.getAuthServerInfo().isJBossBased()) { + String jbossHomePath = suiteContext.getAuthServerInfo().getProperties().get("jbossHome"); + LogChecker.checkJBossServerLog(jbossHomePath); + } + } + +} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainerInfo.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainerInfo.java new file mode 100644 index 0000000000..68ae059869 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainerInfo.java @@ -0,0 +1,64 @@ +package org.keycloak.testsuite.arquillian; + +import java.net.URL; +import java.util.Map; +import org.jboss.arquillian.container.spi.Container; + +/** + * + * @author tkyjovsk + */ +public class ContainerInfo { + + private URL contextRoot; + private Container arquillianContainer; + + public ContainerInfo(Container arquillianContainer) { + if (arquillianContainer == null) { + throw new IllegalArgumentException(); + } + this.arquillianContainer = arquillianContainer; + } + + public Container getArquillianContainer() { + return arquillianContainer; + } + + public Map getProperties() { + return getArquillianContainer().getContainerConfiguration().getContainerProperties(); + } + + public String getQualifier() { + return getArquillianContainer().getName(); + } + + public URL getContextRoot() { + return contextRoot; + } + + public void setContextRoot(URL contextRoot) { + this.contextRoot = contextRoot; + } + + public boolean isAS7() { + return getQualifier().contains("as7"); + } + + public boolean isWildfly() { + return getQualifier().contains("Wildfly"); + } + + public boolean isEAP() { + return getQualifier().contains("eap"); + } + + public boolean isJBossBased() { + return isAS7() || isWildfly() || isEAP(); + } + + @Override + public String toString() { + return getQualifier(); + } + +} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainersTestEnricher.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainersTestEnricher.java deleted file mode 100644 index 376ed9ed3e..0000000000 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainersTestEnricher.java +++ /dev/null @@ -1,362 +0,0 @@ -/* - * Copyright 2016 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; - -import static org.keycloak.testsuite.auth.page.AuthRealm.ADMIN; -import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER; -import static org.keycloak.testsuite.util.WaitUtils.pause; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.LinkedList; -import java.util.concurrent.TimeUnit; - -import org.apache.commons.io.FileUtils; -import org.jboss.arquillian.container.spi.Container; -import org.jboss.arquillian.container.spi.ContainerRegistry; -import org.jboss.arquillian.container.spi.event.StartSuiteContainers; -import org.jboss.arquillian.container.spi.event.StopSuiteContainers; -import org.jboss.arquillian.container.spi.event.container.AfterStart; -import org.jboss.arquillian.container.test.api.ContainerController; -import org.jboss.arquillian.core.api.Event; -import org.jboss.arquillian.core.api.Instance; -import org.jboss.arquillian.core.api.InstanceProducer; -import org.jboss.arquillian.core.api.annotation.Inject; -import org.jboss.arquillian.core.api.annotation.Observes; -import org.jboss.arquillian.test.spi.annotation.ClassScoped; -import org.jboss.arquillian.test.spi.annotation.SuiteScoped; -import org.jboss.arquillian.test.spi.event.suite.BeforeClass; -import org.jboss.arquillian.test.spi.event.suite.BeforeSuite; -import org.jboss.logging.Logger; -import org.keycloak.admin.client.Keycloak; -import org.keycloak.models.Constants; -import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty; -import org.keycloak.testsuite.arquillian.annotation.AppServerContainer; -import org.keycloak.testsuite.util.OAuthClient; - -/** - * - * @author tkyjovsk - * @author vramik - */ -public class ContainersTestEnricher { - - protected final Logger log = Logger.getLogger(this.getClass()); - - @Inject - private Instance containerController; - - @Inject - private Instance containerRegistry; - - @Inject - private Event stopSuiteContainers; - - private String appServerQualifier; - - private static final String AUTH_SERVER_CONTAINER_PROPERTY = "auth.server.container"; - private static final String AUTH_SERVER_CONTAINER_DEFAULT = "auth-server-undertow"; - - @Inject - @SuiteScoped - private InstanceProducer suiteContext; - - @Inject - @ClassScoped - private InstanceProducer testContext; - - @Inject - @ClassScoped - private InstanceProducer adminClient; - - @Inject - @ClassScoped - private InstanceProducer oauthClient; - - private ContainerController controller; - private LinkedList containers; - - private String jbossHomePath; - private final boolean migrationTests = System.getProperty("migration", "false").equals("true"); - private final boolean skipInstallAdapters = System.getProperty("skip.install.adapters", "false").equals("true"); - private boolean alreadyInstalled = false; - private boolean alreadyStopped = false; - private boolean init = false; - - private void init() { - if (!init) { - containers = new LinkedList<>(containerRegistry.get().getContainers()); - } - init = true; - } - - /* - * non-javadoc - * - * Before starting suite containers. Initialization of containers is done - * (only once during class life cycle) - */ - public void startSuiteContainers(@Observes(precedence = 1) StartSuiteContainers event) { - init(); - if (migrationTests) { - log.info("\n\n### Starting keycloak " + System.getProperty("version", "- previous") + " ###\n"); - } - } - - /* - * non-javadoc - * - * After start container. Server logs are checked (in case jboss based container). - * In case of migration scenario: previous container is stopped. - */ - public void afterStart(@Observes AfterStart event) throws IOException, InterruptedException { - Container container = containers.pollFirst(); - - if (isJBossBased(container)) { - jbossHomePath = container.getContainerConfiguration().getContainerProperties().get("jbossHome"); - log.debug("jbossHome: " + jbossHomePath + "\n"); - } - checkServerLog(jbossHomePath); - - if (migrationTests && !alreadyStopped) { - log.info("\n\n### Stopping keycloak " + System.getProperty("version", "- previous") + " ###\n"); - stopSuiteContainers.fire(new StopSuiteContainers()); - log.info("\n\n### Starting keycloak current version ###\n"); - alreadyStopped = true; - } - installAdapters(container); - } - - /* - * non-javadoc - * - * check server logs whether there are no ERRORs or SEVEREs - */ - private void checkServerLog(String jbossHomePath) throws IOException { - if (jbossHomePath != null && System.getProperty("check.server.log", "true").equals("true")) { - File serverLog = new File(jbossHomePath + "/standalone/log/server.log"); - String serverLogContent = FileUtils.readFileToString(serverLog); - - boolean containsError - = serverLogContent.contains("ERROR") - || serverLogContent.contains("SEVERE") - || serverLogContent.contains("Exception "); - //There is expected string "Exception" in server log: Adding provider - //singleton org.keycloak.services.resources.ModelExceptionMapper - - if (containsError) { - throw new RuntimeException(serverLog.getPath() + " contains ERROR."); - } - log.info(serverLog.getPath() + " doesn't contain Error"); - } - } - - public void beforeSuite(@Observes BeforeSuite event) { - suiteContext.set(new SuiteContext()); - } - - public void startContainers(@Observes(precedence = -1) BeforeClass event) { - controller = containerController.get(); - - Class testClass = event.getTestClass().getJavaClass(); - appServerQualifier = getAppServerQualifier(testClass); - - if (!controller.isStarted(appServerQualifier)) { - controller.start(appServerQualifier); - } - - initializeTestContext(testClass); - initializeAdminClient(); - initializeOAuthClient(); - } - - private void initializeTestContext(Class testClass) { - String authServerContextRootStr = getAuthServerContextRootFromSystemProperty(); - String appServerContextRootStr = isRelative(testClass) - ? authServerContextRootStr - : getAppServerContextRootFromSystemProperty(); - try { - URL authServerContextRoot = new URL(authServerContextRootStr); - URL appServerContextRoot = new URL(appServerContextRootStr); - - testContext.set(new TestContext(authServerContextRoot, appServerContextRoot)); - - } catch (MalformedURLException ex) { - throw new IllegalStateException("Malformed url.", ex); - } - } - - private void initializeAdminClient() { - adminClient.set(Keycloak.getInstance( - getAuthServerContextRootFromSystemProperty() + "/auth", - MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID)); - } - - private void initializeOAuthClient() { - oauthClient.set(new OAuthClient(getAuthServerContextRootFromSystemProperty() + "/auth")); - } - - /** - * - * @param testClass - * @param annotationClass - * @return testClass or the nearest superclass of testClass annotated with - * annotationClass - */ - public static Class getNearestSuperclassWithAnnotation(Class testClass, Class annotationClass) { - return testClass.isAnnotationPresent(annotationClass) ? testClass - : (testClass.getSuperclass().equals(Object.class) ? null // stop recursion - : getNearestSuperclassWithAnnotation(testClass.getSuperclass(), annotationClass)); // continue recursion - } - - public static String getAuthServerQualifier() { - return System.getProperty( - AUTH_SERVER_CONTAINER_PROPERTY, - AUTH_SERVER_CONTAINER_DEFAULT); - } - - public static String getAppServerQualifier(Class testClass) { - Class annotatedClass = getNearestSuperclassWithAnnotation(testClass, AppServerContainer.class); - - String appServerQ = (annotatedClass == null ? null - : annotatedClass.getAnnotation(AppServerContainer.class).value()); - - return appServerQ == null || appServerQ.isEmpty() - ? getAuthServerQualifier() // app server == auth server - : appServerQ; - } - - public static boolean hasAppServerContainerAnnotation(Class testClass) { - return getNearestSuperclassWithAnnotation(testClass, AppServerContainer.class) != null; - } - - public static boolean isRelative(Class testClass) { - return getAppServerQualifier(testClass).equals(getAuthServerQualifier()); - } - - public static String getAdapterLibsLocationProperty(Class testClass) { - Class annotatedClass = getNearestSuperclassWithAnnotation(testClass, AdapterLibsLocationProperty.class); - return (annotatedClass == null ? null - : annotatedClass.getAnnotation(AdapterLibsLocationProperty.class).value()); - } - - public static boolean isWildflyAppServer(Class testClass) { - return getAppServerQualifier(testClass).contains("wildfly"); - } - - public static boolean isTomcatAppServer(Class testClass) { - return getAppServerQualifier(testClass).contains("tomcat"); - } - - public static boolean isOSGiAppServer(Class testClass) { - String q = getAppServerQualifier(testClass); - return q.contains("karaf") || q.contains("fuse"); - } - - public static String getAuthServerContextRootFromSystemProperty() { - // TODO find if this can be extracted from ARQ metadata instead of System properties - boolean sslRequired = Boolean.parseBoolean(System.getProperty("auth.server.ssl.required")); - if (sslRequired) { - return "https://localhost:" + Integer.parseInt(System.getProperty("auth.server.https.port", "8543")); - } - return "http://localhost:" + Integer.parseInt(System.getProperty("auth.server.http.port", "8180")); - } - - public static String getAppServerContextRootFromSystemProperty() { - boolean sslRequired = Boolean.parseBoolean(System.getProperty("app.server.ssl.required")); - if (sslRequired) { - return "https://localhost:" + Integer.parseInt(System.getProperty("app.server.https.port", "8643")); - } - return "http://localhost:" + Integer.parseInt(System.getProperty("app.server.http.port", "8280")); - } - - private void installAdapters(Container container) throws InterruptedException, IOException { - if (!alreadyInstalled && !skipInstallAdapters && isJBossBased(container)) { - File bin = new File(jbossHomePath + "/bin"); - String command = "java -jar " + jbossHomePath + "/bin/client/jboss-cli-client.jar"; - String adapterScript = "adapter-install.cli"; - String samlAdapterScript = "adapter-install-saml.cli"; - String managementPort = container.getContainerConfiguration().getContainerProperties().get("managementPort"); - - String controllerArg = " --controller=localhost:" + managementPort; - if (new File(bin, adapterScript).exists()) { - log.info("Installing adapter to app server via cli script"); - execCommand(command + " --connect --file=" + adapterScript + controllerArg, bin); - } - if (new File(bin, samlAdapterScript).exists()) { - log.info("Installing saml adapter to app server via cli script"); - execCommand(command + " --connect --file=" + samlAdapterScript + controllerArg, bin); - } - if (new File(bin, adapterScript).exists() || new File(bin, samlAdapterScript).exists()) { - log.info("Restarting container"); - execCommand(command + " --connect --command=reload" + controllerArg, bin); - log.info("Container restarted"); - pause(5000); - checkServerLog(jbossHomePath); - } - if (container.getName().startsWith("app-server")) { - alreadyInstalled = true; - } - } - } - - private void execCommand(String command, File dir) throws IOException, InterruptedException { - Process process = Runtime.getRuntime().exec(command, null, dir); - if (process.waitFor(10, TimeUnit.SECONDS)) { - if (process.exitValue() != 0) { - getOutput("ERROR", process.getErrorStream()); - throw new RuntimeException("Adapter installation failed. Process exitValue: " - + process.exitValue()); - } - getOutput("OUTPUT", process.getInputStream()); - log.debug("process.isAlive(): " + process.isAlive()); - } else { - if (process.isAlive()) { - process.destroyForcibly(); - } - throw new RuntimeException("Timeout after 10 seconds."); - } - } - - private void getOutput(String type, InputStream is) throws IOException { - BufferedReader reader = new BufferedReader(new InputStreamReader(is)); - StringBuilder builder = new StringBuilder(); - builder.append("<").append(type).append(">"); - System.out.println(builder); - builder = new StringBuilder(); - while (reader.ready()) { - System.out.println(reader.readLine()); - } - builder.append(""); - System.out.println(builder); - } - - private boolean isJBossBased(Container container) { - if (container == null) { - return false; - } - return container.getName().matches("a.*-server-wildfly") - || container.getName().matches("a.*-server-eap.") - || container.getName().equals("app-server-as7"); - } -} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java index 74e20c1e1a..da482a8627 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java @@ -37,8 +37,12 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import static org.keycloak.testsuite.arquillian.AppServerTestEnricher.getAdapterLibsLocationProperty; +import static org.keycloak.testsuite.arquillian.AppServerTestEnricher.hasAppServerContainerAnnotation; +import static org.keycloak.testsuite.arquillian.AppServerTestEnricher.isRelative; +import static org.keycloak.testsuite.arquillian.AppServerTestEnricher.isTomcatAppServer; -import static org.keycloak.testsuite.arquillian.ContainersTestEnricher.*; +import static org.keycloak.testsuite.arquillian.AuthServerTestEnricher.*; import static org.keycloak.testsuite.util.IOUtil.*; ; @@ -122,7 +126,7 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor { adapterConfig.setAuthServerUrl("/auth"); // ac.setRealmKey(null); // TODO verify if realm key is required for relative scneario } else { - adapterConfig.setAuthServerUrl(getAuthServerContextRootFromSystemProperty() + "/auth"); + adapterConfig.setAuthServerUrl(getAuthServerContextRoot() + "/auth"); adapterConfig.setRealmKey(REALM_KEY); } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentTargetModifier.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentTargetModifier.java index b45d50f689..b867c7ce4e 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentTargetModifier.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentTargetModifier.java @@ -23,7 +23,7 @@ import org.jboss.arquillian.container.spi.client.deployment.TargetDescription; import org.jboss.arquillian.container.test.impl.client.deployment.AnnotationDeploymentScenarioGenerator; import org.jboss.arquillian.test.spi.TestClass; import org.jboss.logging.Logger; -import static org.keycloak.testsuite.arquillian.ContainersTestEnricher.*; +import static org.keycloak.testsuite.arquillian.AppServerTestEnricher.getAppServerQualifier; /** * Changes target container for all Arquillian deployments based on value of diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/KeycloakArquillianExtension.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/KeycloakArquillianExtension.java index 621483c2fd..7154b8a335 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/KeycloakArquillianExtension.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/KeycloakArquillianExtension.java @@ -47,7 +47,8 @@ public class KeycloakArquillianExtension implements LoadableExtension { builder .service(DeploymentScenarioGenerator.class, DeploymentTargetModifier.class) .service(ApplicationArchiveProcessor.class, DeploymentArchiveProcessor.class) - .observer(ContainersTestEnricher.class); + .observer(AuthServerTestEnricher.class) + .observer(AppServerTestEnricher.class); builder .service(DeployableContainer.class, CustomUndertowContainer.class); diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/SuiteContext.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/SuiteContext.java index fb91a7b196..cf58916821 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/SuiteContext.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/SuiteContext.java @@ -14,11 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.keycloak.testsuite.arquillian; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +import org.jboss.arquillian.container.spi.Container; import static org.keycloak.testsuite.util.MailServerConfiguration.*; /** @@ -27,10 +29,18 @@ import static org.keycloak.testsuite.util.MailServerConfiguration.*; */ public final class SuiteContext { + private final List arquillianContainers; + + private ContainerInfo authServerInfo; + private final List authServerBackendsInfo = new ArrayList<>(); + + private ContainerInfo migratedAuthServerInfo; + private boolean adminPasswordUpdated; private final Map smtpServer = new HashMap<>(); - - public SuiteContext() { + + public SuiteContext(List arquillianContainers) { + this.arquillianContainers = arquillianContainers; this.adminPasswordUpdated = false; smtpServer.put("from", FROM); smtpServer.put("host", HOST); @@ -48,4 +58,44 @@ public final class SuiteContext { public Map getSmtpServer() { return smtpServer; } + + public ContainerInfo getAuthServerInfo() { + return authServerInfo; + } + + public void setAuthServerInfo(ContainerInfo authServerInfo) { + this.authServerInfo = authServerInfo; + } + + public List getAuthServerBackendsInfo() { + return authServerBackendsInfo; + } + + public ContainerInfo getMigratedAuthServerInfo() { + return migratedAuthServerInfo; + } + + public void setMigratedAuthServerInfo(ContainerInfo migratedAuthServerInfo) { + this.migratedAuthServerInfo = migratedAuthServerInfo; + } + + public boolean isAuthServerCluster() { + return !authServerBackendsInfo.isEmpty(); + } + + public boolean isAuthServerMigrationEnabled() { + return migratedAuthServerInfo != null; + } + + public List getArquillianContainers() { + return arquillianContainers; + } + + @Override + public String toString() { + return "SUITE CONTEXT:\n" + + "Auth server: " + authServerInfo.getQualifier() + "\n" + +(isAuthServerCluster() ? "Auth server cluster: " + getAuthServerBackendsInfo().size() + " nodes+\n" : ""); + } + } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/TestContext.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/TestContext.java index b4c67ef61f..673bc7c4fd 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/TestContext.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/TestContext.java @@ -14,10 +14,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.keycloak.testsuite.arquillian; -import java.net.URL; +import java.util.ArrayList; +import java.util.List; /** * @@ -25,29 +25,21 @@ import java.net.URL; */ public final class TestContext { - private URL authServerContextRoot; - private URL appServerContextRoot; + private final SuiteContext suiteContext; + + private final Class testClass; + + private ContainerInfo appServerInfo; + private final List appServerBackendsInfo = new ArrayList<>(); private boolean adminLoggedIn; - public TestContext() { + public TestContext(SuiteContext suiteContext, Class testClass) { + this.suiteContext = suiteContext; + this.testClass = testClass; this.adminLoggedIn = false; } - public TestContext(URL authServerContextRoot, URL appServerContextRoot) { - this(); - this.authServerContextRoot = authServerContextRoot; - this.appServerContextRoot = appServerContextRoot; - } - - public URL getAuthServerContextRoot() { - return authServerContextRoot; - } - - public URL getAppServerContextRoot() { - return appServerContextRoot; - } - public boolean isAdminLoggedIn() { return adminLoggedIn; } @@ -56,12 +48,44 @@ public final class TestContext { this.adminLoggedIn = adminLoggedIn; } - public void setAuthServerContextRoot(URL authServerContextRoot) { - this.authServerContextRoot = authServerContextRoot; + public ContainerInfo getAppServerInfo() { + return appServerInfo; } - public void setAppServerContextRoot(URL appServerContextRoot) { - this.appServerContextRoot = appServerContextRoot; + public void setAppServerInfo(ContainerInfo appServerInfo) { + this.appServerInfo = appServerInfo; + } + + public List getAppServerBackendsInfo() { + return appServerBackendsInfo; + } + + public Class getTestClass() { + return testClass; + } + + public boolean isAdapterTest() { + return appServerInfo != null; + } + + public boolean isRelativeAdapterTest() { + return isAdapterTest() + && appServerInfo.getQualifier().equals( + suiteContext.getAuthServerInfo().getQualifier()); // app server == auth server + } + + public boolean isClusteredAdapterTest() { + return isAdapterTest() && !appServerBackendsInfo.isEmpty(); + } + + public SuiteContext getSuiteContext() { + return suiteContext; + } + + @Override + public String toString() { + return "TEST CONTEXT: " + getTestClass().getCanonicalName() + "\n" + + (isAdapterTest() ? "App server container: " + getAppServerInfo() + "\n" : ""); } } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/URLProvider.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/URLProvider.java index f883f6477f..301fc866a6 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/URLProvider.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/URLProvider.java @@ -33,6 +33,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.HashSet; import java.util.Set; +import org.keycloak.testsuite.arquillian.SuiteContext; public class URLProvider extends URLResourceProvider { @@ -43,6 +44,8 @@ public class URLProvider extends URLResourceProvider { private final boolean appServerSslRequired = Boolean.parseBoolean(System.getProperty("app.server.ssl.required")); + @Inject + Instance suiteContext; @Inject Instance testContext; @@ -97,10 +100,10 @@ public class URLProvider extends URLResourceProvider { // inject context roots if annotation present for (Annotation a : qualifiers) { if (AuthServerContext.class.isAssignableFrom(a.annotationType())) { - return testContext.get().getAuthServerContextRoot(); + return suiteContext.get().getAuthServerInfo().getContextRoot(); } if (AppServerContext.class.isAssignableFrom(a.annotationType())) { - return testContext.get().getAppServerContextRoot(); + return testContext.get().getAppServerInfo().getContextRoot(); } } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthServer.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthServer.java index 7dae6b6905..14f1e266f0 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthServer.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/AuthServer.java @@ -41,11 +41,11 @@ public class AuthServer extends AuthServerContextRoot { return uri.getScheme() + "://" + uri.getAuthority() + "/auth"; } - @ArquillianResource - protected Keycloak keycloak; - - public Keycloak keycloak() { - return keycloak; - } +// @ArquillianResource +// protected Keycloak keycloak; +// +// public Keycloak keycloak() { +// return keycloak; +// } } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/AccountManagement.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/AccountManagement.java index 4661df89dd..ba45448473 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/AccountManagement.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/AccountManagement.java @@ -101,9 +101,9 @@ public class AccountManagement extends AuthRealm { save.click(); } - public RealmResource realmResource() { - return keycloak().realm(getAuthRealm()); - } +// public RealmResource realmResource() { +// return keycloak().realm(getAuthRealm()); +// } public void waitForAccountLinkPresent() { waitUntilElement(accountLink, "account link should be present").is().present(); diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleRealm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleRealm.java index 081b1d40ff..fa42371cfd 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleRealm.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleRealm.java @@ -59,9 +59,9 @@ public class AdminConsoleRealm extends AdminConsoleRealmsRoot { return configureMenu; } - public RealmResource realmResource() { - return realmsResource().realm(getConsoleRealm()); - } +// public RealmResource realmResource() { +// return realmsResource().realm(getConsoleRealm()); +// } public class ConfigureMenu { diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleRealmsRoot.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleRealmsRoot.java index 5e3048fea5..467dc21996 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleRealmsRoot.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/AdminConsoleRealmsRoot.java @@ -59,8 +59,8 @@ public class AdminConsoleRealmsRoot extends AdminConsole { @FindBy(css = "realm-selector") protected RealmSelector realmSelector; - public RealmsResource realmsResource() { - return keycloak.realms(); - } +// public RealmsResource realmsResource() { +// return keycloak.realms(); +// } } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/IOUtil.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/IOUtil.java index 36c692bfcf..23103d3339 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/IOUtil.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/IOUtil.java @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.keycloak.testsuite.util; import org.keycloak.representations.idm.RealmRepresentation; @@ -33,6 +32,8 @@ import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import java.io.*; +import java.util.concurrent.TimeUnit; +import org.jboss.logging.Logger; /** * @@ -40,6 +41,8 @@ import java.io.*; */ public class IOUtil { + private static final Logger log = Logger.getLogger(IOUtil.class); + public static T loadJson(InputStream is, Class type) { try { return JsonSerialization.readValue(is, type); @@ -71,7 +74,7 @@ public class IOUtil { DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); return dBuilder.parse(is); - } catch (ParserConfigurationException|SAXException|IOException e) { + } catch (ParserConfigurationException | SAXException | IOException e) { throw new RuntimeException(e); } } @@ -99,4 +102,36 @@ public class IOUtil { } node.setTextContent(node.getTextContent().replace(regex, replacement)); } + + public static void execCommand(String command, File dir) throws IOException, InterruptedException { + Process process = Runtime.getRuntime().exec(command, null, dir); + if (process.waitFor(10, TimeUnit.SECONDS)) { + if (process.exitValue() != 0) { + getOutput("ERROR", process.getErrorStream()); + throw new RuntimeException("Adapter installation failed. Process exitValue: " + + process.exitValue()); + } + getOutput("OUTPUT", process.getInputStream()); + log.debug("process.isAlive(): " + process.isAlive()); + } else { + if (process.isAlive()) { + process.destroyForcibly(); + } + throw new RuntimeException("Timeout after 10 seconds."); + } + } + + public static void getOutput(String type, InputStream is) throws IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + StringBuilder builder = new StringBuilder(); + builder.append("<").append(type).append(">"); + System.out.println(builder); + builder = new StringBuilder(); + while (reader.ready()) { + System.out.println(reader.readLine()); + } + builder.append(""); + System.out.println(builder); + } + } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/LogChecker.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/LogChecker.java new file mode 100644 index 0000000000..8e16b3492e --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/LogChecker.java @@ -0,0 +1,37 @@ +package org.keycloak.testsuite.util; + +import java.io.File; +import java.io.IOException; +import org.apache.commons.io.FileUtils; +import org.jboss.logging.Logger; + +/** + * + * @author vramik + * @author tkyjovsk + */ +public class LogChecker { + + private static final Logger log = Logger.getLogger(LogChecker.class); + + public static void checkServerLog(File logFile) throws IOException { + log.info(String.format("Checking server log: '%s'", logFile.getAbsolutePath())); + String logContent = FileUtils.readFileToString(logFile); + + boolean containsError + = logContent.contains("ERROR") + || logContent.contains("SEVERE") + || logContent.contains("Exception "); + + //There is expected string "Exception" in server log: Adding provider + //singleton org.keycloak.services.resources.ModelExceptionMapper + if (containsError) { + throw new RuntimeException(String.format("Server log file contains ERROR: '%s'", logFile.getPath())); + } + } + + public static void checkJBossServerLog(String jbossHome) throws IOException { + checkServerLog(new File(jbossHome + "/standalone/log/server.log")); + } + +} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java index 9d3040f284..92dc9c57e2 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.keycloak.testsuite; import org.keycloak.testsuite.arquillian.TestContext; @@ -33,9 +32,12 @@ import org.junit.Before; import org.junit.runner.RunWith; import org.keycloak.admin.client.Keycloak; import org.keycloak.admin.client.resource.RealmResource; +import org.keycloak.admin.client.resource.RealmsResource; +import org.keycloak.models.Constants; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.UserRepresentation; import static org.keycloak.testsuite.admin.Users.setPasswordFor; +import org.keycloak.testsuite.arquillian.AuthServerTestEnricher; import org.keycloak.testsuite.arquillian.SuiteContext; import org.keycloak.testsuite.auth.page.WelcomePage; import org.keycloak.testsuite.util.OAuthClient; @@ -66,11 +68,9 @@ public abstract class AbstractKeycloakTest { @ArquillianResource protected TestContext testContext; - - @ArquillianResource + protected Keycloak adminClient; - @ArquillianResource protected OAuthClient oauthClient; protected List testRealmReps; @@ -100,6 +100,11 @@ public abstract class AbstractKeycloakTest { @Before public void beforeAbstractKeycloakTest() { + adminClient = Keycloak.getInstance(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth", + MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID); + oauthClient = new OAuthClient(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth"); + + adminUser = createAdminUserRepresentation(); setDefaultPageUriParameters(); @@ -195,5 +200,9 @@ public abstract class AbstractKeycloakTest { public void removeRealm(RealmRepresentation realm) { adminClient.realms().realm(realm.getRealm()).remove(); } + + public RealmsResource realmsResouce() { + return adminClient.realms(); + } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/ContainersTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/ContainersTest.java new file mode 100644 index 0000000000..27053aef54 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/ContainersTest.java @@ -0,0 +1,34 @@ +package org.keycloak.testsuite; + +import java.util.List; +import org.jboss.arquillian.container.test.api.ContainerController; +import org.jboss.arquillian.test.api.ArquillianResource; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import org.junit.Test; +import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.testsuite.arquillian.AuthServerTestEnricher; + +/** + * + * @author tkyjovsk + */ +public class ContainersTest extends AbstractKeycloakTest { + + @ArquillianResource + ContainerController controller; + + @Override + public void addTestRealms(List testRealms) { + } + + + @Test + public void testAuthServer() { + + log.info("AUTH SERVER should be started."); + assertTrue(controller.isStarted(AuthServerTestEnricher.getAuthServerQualifier())); + + } + +} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java index fa115af72b..656df2fe2c 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java @@ -25,7 +25,7 @@ import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.testsuite.AbstractAuthTest; import org.keycloak.testsuite.adapter.page.AppServerContextRoot; -import org.keycloak.testsuite.arquillian.ContainersTestEnricher; +import org.keycloak.testsuite.arquillian.AuthServerTestEnricher; import org.keycloak.testsuite.arquillian.annotation.AppServerContainer; import java.io.IOException; @@ -78,7 +78,7 @@ public abstract class AbstractAdapterTest extends AbstractAuthTest { public abstract void addAdapterTestRealms(List testRealms); public boolean isRelative() { - return ContainersTestEnricher.isRelative(this.getClass()); + return testContext.isRelativeAdapterTest(); } protected void modifyClientRedirectUris(RealmRepresentation realm, String regex, String replacement) { diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/AbstractClientRegistrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/AbstractClientRegistrationTest.java index fc572a18b0..c7085b387d 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/AbstractClientRegistrationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/AbstractClientRegistrationTest.java @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.keycloak.testsuite.client; import org.junit.After; @@ -46,7 +45,7 @@ public abstract class AbstractClientRegistrationTest extends AbstractKeycloakTes @Before public void before() throws Exception { - reg = ClientRegistration.create().url(testContext.getAuthServerContextRoot() + "/auth", "test").build(); + reg = ClientRegistration.create().url(suiteContext.getAuthServerInfo().getContextRoot() + "/auth", "test").build(); } @After diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/AdapterInstallationConfigTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/AdapterInstallationConfigTest.java index 55a9475039..427202548d 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/AdapterInstallationConfigTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/AdapterInstallationConfigTest.java @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.keycloak.testsuite.client; import org.junit.Before; @@ -87,7 +86,7 @@ public class AdapterInstallationConfigTest extends AbstractClientRegistrationTes AdapterConfig config = reg.getAdapterConfig(client.getClientId()); assertNotNull(config); - assertEquals(testContext.getAuthServerContextRoot() + "/auth", config.getAuthServerUrl()); + assertEquals(suiteContext.getAuthServerInfo().getContextRoot() + "/auth", config.getAuthServerUrl()); assertEquals("test", config.getRealm()); assertEquals(1, config.getCredentials().size()); 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 8c8f9b2a96..57e1692dcd 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml +++ b/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml @@ -1,19 +1,19 @@ +~ Copyright 2016 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. +--> target/deployments - - - - - - ${migration.kc16} - org.jboss.as.arquillian.container.managed.ManagedDeployableContainer - ${keycloak.migration.home} - - -Dkeycloak.migration.action=import - -Dkeycloak.migration.provider=singleFile - -Dkeycloak.migration.file=${keycloak.migration.file} - -Dkeycloak.migration.strategy=OVERWRITE_EXISTING - -Dkeycloak.migration.realmName=Migration - -Djboss.socket.binding.port-offset=${auth.server.port.offset} - -Xms64m -Xmx512m -XX:MaxPermSize=256m - - ${auth.server.management.port} - ${startup.timeout.sec} - - - - - - ${migration.kc15} - org.jboss.as.arquillian.container.managed.ManagedDeployableContainer - ${keycloak.migration.home} - - -Dkeycloak.migration.action=import - -Dkeycloak.migration.provider=singleFile - -Dkeycloak.migration.file=${keycloak.migration.file} - -Dkeycloak.migration.strategy=OVERWRITE_EXISTING - -Dkeycloak.migration.realmName=Migration - -Djboss.socket.binding.port-offset=${auth.server.port.offset} - -Xms64m -Xmx512m -XX:MaxPermSize=256m - - ${auth.server.management.port} - ${startup.timeout.sec} - - - - - - ${migration.kc14} - org.jboss.as.arquillian.container.managed.ManagedDeployableContainer - ${keycloak.migration.home} - -Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m - ${auth.server.management.port} - ${startup.timeout.sec} - - - - - - ${migration.kc13} - org.jboss.as.arquillian.container.managed.ManagedDeployableContainer - ${keycloak.migration.home} - -Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m - ${auth.server.management.port} - ${startup.timeout.sec} - - - - - - ${migration.kc12} - org.jboss.as.arquillian.container.managed.ManagedDeployableContainer - ${keycloak.migration.home} - -Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m - ${auth.server.management.port} - ${startup.timeout.sec} - - - @@ -140,6 +66,37 @@ + + + + ${auth.server.wildfly.cluster} + org.jboss.as.arquillian.container.managed.ManagedDeployableContainer + ${wildfly.home} + + -Djboss.socket.binding.port-offset=${auth.server.port.offset} + -Xms64m -Xmx512m -XX:MaxPermSize=256m + ${adapter.test.props} + + ${auth.server.management.port} + ${startup.timeout.sec} + + + + + ${auth.server.wildfly.cluster} + org.jboss.as.arquillian.container.managed.ManagedDeployableContainer + ${keycloak.backend1.home} + + -Djboss.socket.binding.port-offset=${auth.server.backend1.port.offset} + -Xms64m -Xmx512m -XX:MaxPermSize=256m + ${adapter.test.props} + + ${auth.server.backend1.management.port} + ${startup.timeout.sec} + + + + ${auth.server.eap7} @@ -150,5 +107,79 @@ ${auth.server.management.port} + + + + + ${migration.kc16} + org.jboss.as.arquillian.container.managed.ManagedDeployableContainer + ${keycloak.migration.home} + + -Dkeycloak.migration.action=import + -Dkeycloak.migration.provider=singleFile + -Dkeycloak.migration.file=${keycloak.migration.file} + -Dkeycloak.migration.strategy=OVERWRITE_EXISTING + -Dkeycloak.migration.realmName=Migration + -Djboss.socket.binding.port-offset=${auth.server.port.offset} + -Xms64m -Xmx512m -XX:MaxPermSize=256m + + ${auth.server.management.port} + ${startup.timeout.sec} + + + + + + ${migration.kc15} + org.jboss.as.arquillian.container.managed.ManagedDeployableContainer + ${keycloak.migration.home} + + -Dkeycloak.migration.action=import + -Dkeycloak.migration.provider=singleFile + -Dkeycloak.migration.file=${keycloak.migration.file} + -Dkeycloak.migration.strategy=OVERWRITE_EXISTING + -Dkeycloak.migration.realmName=Migration + -Djboss.socket.binding.port-offset=${auth.server.port.offset} + -Xms64m -Xmx512m -XX:MaxPermSize=256m + + ${auth.server.management.port} + ${startup.timeout.sec} + + + + + + ${migration.kc14} + org.jboss.as.arquillian.container.managed.ManagedDeployableContainer + ${keycloak.migration.home} + -Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m + ${auth.server.management.port} + ${startup.timeout.sec} + + + + + + ${migration.kc13} + org.jboss.as.arquillian.container.managed.ManagedDeployableContainer + ${keycloak.migration.home} + -Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m + ${auth.server.management.port} + ${startup.timeout.sec} + + + + + + ${migration.kc12} + org.jboss.as.arquillian.container.managed.ManagedDeployableContainer + ${keycloak.migration.home} + -Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m + ${auth.server.management.port} + ${startup.timeout.sec} + + + + diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/Client.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/Client.java index bb70843df8..864ebeef15 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/Client.java +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/Client.java @@ -108,8 +108,6 @@ public class Client extends Clients { } - public ClientResource clientResource() { - return clientsResource().get(getId()); - } + } diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/Clients.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/Clients.java index 58fac4dfbc..945e72fe0b 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/Clients.java +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/Clients.java @@ -126,8 +126,4 @@ public class Clients extends AdminConsoleRealm { } } - public ClientsResource clientsResource() { - return realmResource().clients(); - } - } diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/roles/ClientRoles.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/roles/ClientRoles.java index 3542af2d86..67bbf529bf 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/roles/ClientRoles.java +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/roles/ClientRoles.java @@ -22,9 +22,5 @@ public class ClientRoles extends Client { public RolesTable roles() { return table; } - - public RolesResource rolesResource() { - return clientResource().roles(); - } } diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/idp/IdentityProviderSettings.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/idp/IdentityProviderSettings.java index 275ddf493b..f3f91a7c45 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/idp/IdentityProviderSettings.java +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/idp/IdentityProviderSettings.java @@ -92,8 +92,4 @@ public class IdentityProviderSettings extends AdminConsoleRealm { return rows; } - public IdentityProvidersResource identityProviders() { - return realmResource().identityProviders(); - } - } diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/roles/Roles.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/roles/Roles.java index 910e47032c..6c862557c5 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/roles/Roles.java +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/roles/Roles.java @@ -35,8 +35,4 @@ public class Roles extends AdminConsoleRealm { } - public RolesResource rolesResource() { - return realmResource().roles(); - } - } diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/User.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/User.java index fba2adb83f..7cea05cd9f 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/User.java +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/User.java @@ -1,6 +1,5 @@ package org.keycloak.testsuite.console.page.users; -import org.keycloak.admin.client.resource.UserResource; import org.keycloak.testsuite.console.page.fragment.Breadcrumb; import static org.keycloak.testsuite.console.page.fragment.Breadcrumb.BREADCRUMB_XPATH; import org.openqa.selenium.WebElement; @@ -76,8 +75,4 @@ public class User extends Users { } - public UserResource userResource() { - return usersResource().get(getId()); - } - } diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/UserRoleMappings.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/UserRoleMappings.java index 3a05b68ab8..32c6bac998 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/UserRoleMappings.java +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/UserRoleMappings.java @@ -20,9 +20,5 @@ public class UserRoleMappings extends User { public UserRoleMappingsForm form() { return form; } - - public RoleMappingResource roleMappingResource() { - return userResource().roles(); - } } diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/Users.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/Users.java index d5ffcb5027..9e083a7117 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/Users.java +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/Users.java @@ -22,7 +22,6 @@ import org.openqa.selenium.support.FindBy; import java.util.ArrayList; import java.util.List; -import org.keycloak.admin.client.resource.UsersResource; import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.testsuite.console.page.AdminConsoleRealm; @@ -135,8 +134,4 @@ public class Users extends AdminConsoleRealm { } - public UsersResource usersResource() { - return realmResource().users(); - } - } diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/AbstractConsoleTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/AbstractConsoleTest.java index eb2fb5b883..633b550f8d 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/AbstractConsoleTest.java +++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/AbstractConsoleTest.java @@ -17,7 +17,6 @@ */ package org.keycloak.testsuite.console; -import org.jboss.arquillian.graphene.findby.FindByJQuery; import org.jboss.arquillian.graphene.page.Page; import static org.junit.Assert.assertTrue; import org.junit.Before; diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java index 0847294b1b..f646675d20 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java +++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java @@ -8,6 +8,8 @@ import java.util.Map; import org.jboss.arquillian.graphene.page.Page; import static org.junit.Assert.assertEquals; import org.junit.Before; +import org.keycloak.admin.client.resource.ClientResource; +import org.keycloak.admin.client.resource.ClientsResource; import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ProtocolMapperRepresentation; import static org.keycloak.testsuite.auth.page.login.OIDCLogin.OIDC; @@ -50,7 +52,7 @@ public abstract class AbstractClientTest extends AbstractConsoleTest { public final String TEST_CLIENT_ID = "test-client"; public final String TEST_REDIRECT_URIS = "http://example.test/app/*"; - + @Page protected Clients clientsPage; @Page @@ -87,12 +89,12 @@ public abstract class AbstractClientTest extends AbstractConsoleTest { client.setConsentRequired(false); return client; } - + public static ClientRepresentation createOidcClientRep(OidcAccessType accessType, String clientId, String... redirectUris) { ClientRepresentation client = createClientRep(clientId); - + client.setProtocol(OIDC); - + switch (accessType) { case BEARER_ONLY: client.setBearerOnly(true); @@ -116,24 +118,24 @@ public abstract class AbstractClientTest extends AbstractConsoleTest { } return client; } - + public static ClientRepresentation createSamlClientRep(String clinetId) { ClientRepresentation client = createClientRep(clinetId); - + client.setProtocol(SAML); - + client.setFrontchannelLogout(true); client.setAttributes(getSAMLAttributes()); - + return client; } - + private static void setRedirectUris(ClientRepresentation client, String... redirectUris) { List redirectUrisList = new ArrayList<>(); redirectUrisList.addAll(Arrays.asList(redirectUris)); client.setRedirectUris(redirectUrisList); } - + protected static void setExpectedWebOrigins(ClientRepresentation client) { List webOrigins = new ArrayList<>(); for (String redirectUri : client.getRedirectUris()) { @@ -143,7 +145,7 @@ public abstract class AbstractClientTest extends AbstractConsoleTest { } client.setWebOrigins(webOrigins); } - + public ClientRepresentation findClientByClientId(String clientId) { ClientRepresentation found = null; for (ClientRepresentation clientRepresentation : testRealmResource().clients().findAll()) { @@ -154,7 +156,7 @@ public abstract class AbstractClientTest extends AbstractConsoleTest { } return found; } - + public void assertClientSettingsEqual(ClientRepresentation c1, ClientRepresentation c2) { assertEqualsStringAttributes(c1.getClientId(), c2.getClientId()); assertEqualsStringAttributes(c1.getName(), c2.getName()); @@ -174,38 +176,37 @@ public abstract class AbstractClientTest extends AbstractConsoleTest { } assertEqualsBooleanAttributes(c1.isSurrogateAuthRequired(), c2.isSurrogateAuthRequired()); assertEqualsBooleanAttributes(c1.isServiceAccountsEnabled(), c2.isServiceAccountsEnabled()); - } - else if (c1.getProtocol().equals(SAML)) { + } else if (c1.getProtocol().equals(SAML)) { assertEqualsBooleanAttributes(c1.isFrontchannelLogout(), c2.isFrontchannelLogout()); } } - + public void assertClientSamlAttributes(Map expected, Map actual) { for (String key : expected.keySet()) { assertEquals("Expected attribute " + key, expected.get(key), actual.get(key)); } } - + protected static Map getSAMLAttributes() { Map attributes = new HashMap<>(); attributes.put(SAML_ASSERTION_SIGNATURE, "true"); attributes.put(SAML_AUTHNSTATEMENT, "false"); - attributes.put(SAML_CLIENT_SIGNATURE, "true"); - attributes.put(SAML_ENCRYPT, "true"); - attributes.put(SAML_FORCE_POST_BINDING, "true"); - attributes.put(SAML_MULTIVALUED_ROLES, "false"); - attributes.put(SAML_SERVER_SIGNATURE, "true"); - attributes.put(SAML_SIGNATURE_ALGORITHM, "RSA_SHA512"); - attributes.put(SAML_ASSERTION_CONSUMER_URL_POST, "http://example0.test"); - attributes.put(SAML_ASSERTION_CONSUMER_URL_REDIRECT, "http://example1.test"); - attributes.put(SAML_FORCE_NAME_ID_FORMAT, "true"); - attributes.put(SAML_NAME_ID_FORMAT, "email"); - attributes.put(SAML_SIGNATURE_CANONICALIZATION_METHOD, "http://www.w3.org/2001/10/xml-exc-c14n#WithComments"); - attributes.put(SAML_SINGLE_LOGOUT_SERVICE_URL_POST, "http://example2.test"); - attributes.put(SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT, "http://example3.test"); + attributes.put(SAML_CLIENT_SIGNATURE, "true"); + attributes.put(SAML_ENCRYPT, "true"); + attributes.put(SAML_FORCE_POST_BINDING, "true"); + attributes.put(SAML_MULTIVALUED_ROLES, "false"); + attributes.put(SAML_SERVER_SIGNATURE, "true"); + attributes.put(SAML_SIGNATURE_ALGORITHM, "RSA_SHA512"); + attributes.put(SAML_ASSERTION_CONSUMER_URL_POST, "http://example0.test"); + attributes.put(SAML_ASSERTION_CONSUMER_URL_REDIRECT, "http://example1.test"); + attributes.put(SAML_FORCE_NAME_ID_FORMAT, "true"); + attributes.put(SAML_NAME_ID_FORMAT, "email"); + attributes.put(SAML_SIGNATURE_CANONICALIZATION_METHOD, "http://www.w3.org/2001/10/xml-exc-c14n#WithComments"); + attributes.put(SAML_SINGLE_LOGOUT_SERVICE_URL_POST, "http://example2.test"); + attributes.put(SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT, "http://example3.test"); return attributes; } - + public ProtocolMapperRepresentation findClientMapperByName(String clientId, String mapperName) { ProtocolMapperRepresentation found = null; for (ProtocolMapperRepresentation mapper : testRealmResource().clients().get(clientId).getProtocolMappers().getMappers()) { @@ -215,4 +216,13 @@ public abstract class AbstractClientTest extends AbstractConsoleTest { } return found; } + + public ClientsResource clientsResource() { + return testRealmResource().clients(); + } + + public ClientResource clientResource(String id) { + return clientsResource().get(id); + } + } diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/clients/ClientSettingsTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/clients/ClientSettingsTest.java index d3aa64fb26..14fff17fd2 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/clients/ClientSettingsTest.java +++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/clients/ClientSettingsTest.java @@ -153,11 +153,11 @@ public class ClientSettingsTest extends AbstractClientTest { c.setPublicClient(true); c.setBearerOnly(true); - Response r = clientsPage.clientsResource().create(c); + Response r = clientsResource().create(c); r.close(); clientSettingsPage.setId(getCreatedId(r)); - c = clientSettingsPage.clientResource().toRepresentation(); + c = clientResource(clientSettingsPage.getId()).toRepresentation(); assertTrue(c.isBearerOnly()); assertTrue(c.isPublicClient()); } diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/events/AdminEventsTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/events/AdminEventsTest.java index c25756491c..ddbaa8cf9c 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/events/AdminEventsTest.java +++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/events/AdminEventsTest.java @@ -18,6 +18,7 @@ import javax.ws.rs.core.Response; import java.util.List; import static org.junit.Assert.assertEquals; +import org.keycloak.admin.client.resource.ClientsResource; import static org.keycloak.testsuite.console.page.clients.CreateClientForm.OidcAccessType.CONFIDENTIAL; @@ -50,12 +51,12 @@ public class AdminEventsTest extends AbstractConsoleTest { @Test public void clientsAdminEventsTest() { newClient = AbstractClientTest.createOidcClientRep(CONFIDENTIAL, "test_client", "http://example.test/test_client/*"); - Response response = clientsPage.clientsResource().create(newClient); + Response response = clientsResource().create(newClient); String id = ApiUtil.getCreatedId(response); response.close(); newClient.setClientId("test_client2"); - clientsPage.clientsResource().get(id).update(newClient); - clientsPage.clientsResource().get(id).remove(); + clientsResource().get(id).update(newClient); + clientsResource().get(id).remove(); adminEventsPage.navigateTo(); adminEventsPage.table().filter(); @@ -85,4 +86,8 @@ public class AdminEventsTest extends AbstractConsoleTest { resultList.get(0).findElement(By.xpath("//td[text()='DELETE']")); resultList.get(0).findElement(By.xpath("//td[text()='clients/" + id + "']")); } + + public ClientsResource clientsResource() { + return testRealmResource().clients(); + } } diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/roles/AbstractRolesTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/roles/AbstractRolesTest.java index 701e798dc4..cb66b8fcb6 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/roles/AbstractRolesTest.java +++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/roles/AbstractRolesTest.java @@ -2,6 +2,7 @@ package org.keycloak.testsuite.console.roles; import org.jboss.arquillian.graphene.page.Page; import org.junit.Before; +import org.keycloak.admin.client.resource.RoleMappingResource; import org.keycloak.testsuite.console.AbstractConsoleTest; import org.keycloak.testsuite.console.page.roles.Roles; import org.keycloak.testsuite.console.page.users.User; diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/roles/DefaultRolesTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/roles/DefaultRolesTest.java index 67baad2604..202d0040c6 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/roles/DefaultRolesTest.java +++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/roles/DefaultRolesTest.java @@ -4,6 +4,7 @@ import org.jboss.arquillian.graphene.page.Page; import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; +import org.keycloak.admin.client.resource.RolesResource; import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.UserRepresentation; import static org.keycloak.testsuite.admin.ApiUtil.createUserWithAdminClient; @@ -31,7 +32,7 @@ public class DefaultRolesTest extends AbstractRolesTest { public void beforeDefaultRolesTest() { // create a role via admin client defaultRoleRep = new RoleRepresentation("default-role", "", false); - rolesPage.rolesResource().create(defaultRoleRep); + rolesResource().create(defaultRoleRep); defaultRolesPage.navigateTo(); // navigate to default roles page @@ -58,4 +59,8 @@ public class DefaultRolesTest extends AbstractRolesTest { assertTrue(userRolesPage.form().isAssignedRole(defaultRoleName)); } + public RolesResource rolesResource() { + return testRealmResource().roles(); + } + } diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/users/AbstractUserTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/users/AbstractUserTest.java index 3ddf8996a4..585080d729 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/users/AbstractUserTest.java +++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/users/AbstractUserTest.java @@ -2,6 +2,8 @@ package org.keycloak.testsuite.console.users; import org.jboss.arquillian.graphene.page.Page; import org.junit.Before; +import org.keycloak.admin.client.resource.UserResource; +import org.keycloak.admin.client.resource.UsersResource; import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.testsuite.console.AbstractConsoleTest; import org.keycloak.testsuite.console.page.users.CreateUser; @@ -35,5 +37,13 @@ public abstract class AbstractUserTest extends AbstractConsoleTest { createUserPage.form().setValues(user); createUserPage.form().save(); } - + + public UsersResource usersResource() { + return testRealmResource().users(); + } + + public UserResource userResource(String id) { + return usersResource().get(id); + } + } From 58084d5ee5442c8587f41a4376cb237348bc5ebc Mon Sep 17 00:00:00 2001 From: Tomas Kyjovsky Date: Fri, 5 Feb 2016 01:07:40 +0100 Subject: [PATCH 2/5] KEYCLOAK-1678 Fixed app-server containers' handling. --- .../arquillian/AppServerTestEnricher.java | 136 ++++++++++-------- .../arquillian/AuthServerTestEnricher.java | 99 +++++++------ .../testsuite/arquillian/ContainerInfo.java | 37 ++++- .../testsuite/arquillian/SuiteContext.java | 12 +- .../adapter/AbstractAdapterTest.java | 1 - .../tests/other/adapters/pom.xml | 13 +- .../other/adapters/wildfly-relative/pom.xml | 62 ++++++-- 7 files changed, 225 insertions(+), 135 deletions(-) diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AppServerTestEnricher.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AppServerTestEnricher.java index b47981b790..47cad7d25f 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AppServerTestEnricher.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AppServerTestEnricher.java @@ -4,7 +4,7 @@ import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; -import org.jboss.arquillian.container.spi.Container; +import org.jboss.arquillian.container.spi.event.container.BeforeDeploy; import org.jboss.arquillian.container.test.api.ContainerController; import org.jboss.arquillian.core.api.Instance; import org.jboss.arquillian.core.api.InstanceProducer; @@ -34,16 +34,15 @@ public class AppServerTestEnricher { private InstanceProducer testContextProducer; private TestContext testContext; - @Inject - private Instance containerController; - public static String getAppServerQualifier(Class testClass) { Class annotatedClass = getNearestSuperclassWithAnnotation(testClass, AppServerContainer.class); String appServerQ = (annotatedClass == null ? null : annotatedClass.getAnnotation(AppServerContainer.class).value()); - return appServerQ; + return appServerQ == null || appServerQ.isEmpty() + ? getAuthServerQualifier() // app server == auth server + : appServerQ; } public static String getAppServerContextRoot() { @@ -60,12 +59,26 @@ public class AppServerTestEnricher { : "http://localhost:" + (httpPort + clusterPortOffset); } - private ContainerInfo initializeAppServerInfo(Container appServerContainer) { - return initializeAppServerInfo(appServerContainer, 0); + public void updateTestContextWithAppServerInfo(@Observes(precedence = 1) BeforeClass event) { + testContext = testContextProducer.get(); + String appServerQualifier = getAppServerQualifier(testContext.getTestClass()); + for (ContainerInfo container : testContext.getSuiteContext().getContainers()) { + if (container.getQualifier().equals(appServerQualifier)) { + testContext.setAppServerInfo(updateWithAppServerInfo(container)); + } + } + // validate app server + if (appServerQualifier != null && testContext.getAppServerInfo() == null) { + throw new RuntimeException(String.format("No app server container matching '%s' was activated. Check if defined and enabled in arquillian.xml.", appServerQualifier)); + } + log.info("\n\n" + testContext); } - private ContainerInfo initializeAppServerInfo(Container appServerContainer, int clusterPortOffset) { - ContainerInfo appServerInfo = new ContainerInfo(appServerContainer); + private ContainerInfo updateWithAppServerInfo(ContainerInfo appServerInfo) { + return updateWithAppServerInfo(appServerInfo, 0); + } + + private ContainerInfo updateWithAppServerInfo(ContainerInfo appServerInfo, int clusterPortOffset) { try { String appServerContextRootStr = isRelative(testContext.getTestClass()) @@ -80,67 +93,74 @@ public class AppServerTestEnricher { return appServerInfo; } - public void updateTestContextWithAppServerInfo(@Observes BeforeClass event) { - testContext = testContextProducer.get(); - String appServerQualifier = getAppServerQualifier(testContext.getTestClass()); - for (Container container : testContext.getSuiteContext().getArquillianContainers()) { - if (container.getContainerConfiguration().getContainerName().equals(appServerQualifier)) { - testContext.setAppServerInfo(initializeAppServerInfo(container)); - } - } - // validate app server - if (appServerQualifier != null && testContext.getAppServerInfo() == null) { - throw new RuntimeException(String.format("No app server container matching '%s' was activated. Check if defined and enabled in arquillian.xml.", appServerQualifier)); - } - log.info("\n\n" + testContext); - } + @Inject + private Instance containerConrollerInstance; public void startAppServer(@Observes(precedence = -1) BeforeClass event) throws MalformedURLException, InterruptedException, IOException { - ContainerController controller = containerController.get(); if (testContext.isAdapterTest()) { - String appServerQualifier = testContext.getAppServerInfo().getQualifier(); - if (!controller.isStarted(appServerQualifier)) { - controller.start(appServerQualifier); + ContainerController controller = containerConrollerInstance.get(); + if (!controller.isStarted(testContext.getAppServerInfo().getQualifier())) { + controller.start(testContext.getAppServerInfo().getQualifier()); } - log.info("\n\n\nAPP SERVER STARTED\n\n\n"); + } + } + + public void installAdapterLibs(@Observes BeforeDeploy event) { + log.info("BEFORE DEPLOY"); + if (testContext.isAdapterTest()) { // install adapter libs on JBoss-based container via CLI -// if (testContext.getAppServerInfo().isJBossBased()) { - installAdapterLibsUsingJBossCLIClient(testContext.getAppServerInfo()); -// } + if (testContext.getAppServerInfo().isJBossBased()) { + try { + installAdapterLibsUsingJBossCLIClient(testContext.getAppServerInfo()); + } catch (InterruptedException | IOException ex) { + throw new RuntimeException("Failed to install adapter libs.", ex); + } + } } } private void installAdapterLibsUsingJBossCLIClient(ContainerInfo appServerInfo) throws InterruptedException, IOException { - - log.info("Installing adapter via CLI client"); - - if (!appServerInfo.isJBossBased()) { - throw new IllegalArgumentException("App server must be JBoss-based to run jboss-cli-client."); - } + if (!appServerInfo.isAdapterLibsInstalled()) { - String jbossHomePath = appServerInfo.getProperties().get("jbossHome"); + if (!appServerInfo.isJBossBased()) { + throw new IllegalArgumentException("App server must be JBoss-based to run jboss-cli-client."); + } - File bin = new File(jbossHomePath + "/bin"); - String command = "java -jar " + jbossHomePath + "/bin/client/jboss-cli-client.jar"; - String adapterScript = "adapter-install.cli"; - String samlAdapterScript = "adapter-install-saml.cli"; - String managementPort = appServerInfo.getProperties().get("managementPort"); + String jbossHomePath = appServerInfo.getProperties().get("jbossHome"); - String controllerArg = " --controller=localhost:" + managementPort; - if (new File(bin, adapterScript).exists()) { - log.info("Installing adapter to app server via cli script"); - execCommand(command + " --connect --file=" + adapterScript + controllerArg, bin); - } - if (new File(bin, samlAdapterScript).exists()) { - log.info("Installing saml adapter to app server via cli script"); - execCommand(command + " --connect --file=" + samlAdapterScript + controllerArg, bin); - } - if (new File(bin, adapterScript).exists() || new File(bin, samlAdapterScript).exists()) { - log.info("Restarting container"); - execCommand(command + " --connect --command=reload" + controllerArg, bin); - log.info("Container restarted"); - pause(5000); - LogChecker.checkJBossServerLog(jbossHomePath); + File bin = new File(jbossHomePath + "/bin"); + + File clientJar = new File(jbossHomePath + "/bin/client/jboss-cli-client.jar"); + if (!clientJar.exists()) { + clientJar = new File(jbossHomePath + "/bin/client/jboss-client.jar"); // AS7 + } + if (!clientJar.exists()) { + throw new IOException("JBoss CLI client JAR not found."); + } + + String command = "java -jar " + clientJar.getAbsolutePath(); + String adapterScript = "adapter-install.cli"; + String samlAdapterScript = "adapter-install-saml.cli"; + String managementPort = appServerInfo.getProperties().get("managementPort"); + + String controllerArg = " --controller=localhost:" + managementPort; + if (new File(bin, adapterScript).exists()) { + log.info("Installing adapter to app server via cli script"); + execCommand(command + " --connect --file=" + adapterScript + controllerArg, bin); + } + if (new File(bin, samlAdapterScript).exists()) { + log.info("Installing saml adapter to app server via cli script"); + execCommand(command + " --connect --file=" + samlAdapterScript + controllerArg, bin); + } + if (new File(bin, adapterScript).exists() || new File(bin, samlAdapterScript).exists()) { + log.info("Restarting container"); + execCommand(command + " --connect --command=reload" + controllerArg, bin); + log.info("Container restarted"); + pause(5000); + LogChecker.checkJBossServerLog(jbossHomePath); + } + + appServerInfo.setAdapterLibsInstalled(true); } } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AuthServerTestEnricher.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AuthServerTestEnricher.java index 86176cb820..5000e3b482 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AuthServerTestEnricher.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AuthServerTestEnricher.java @@ -19,7 +19,8 @@ package org.keycloak.testsuite.arquillian; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; -import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.Set; import org.jboss.arquillian.container.spi.Container; import org.jboss.arquillian.container.spi.ContainerRegistry; @@ -44,79 +45,87 @@ import org.keycloak.testsuite.util.LogChecker; * @author vramik */ public class AuthServerTestEnricher { - + protected final Logger log = Logger.getLogger(this.getClass()); - + @Inject private Instance containerRegistry; - + @Inject private Instance containerController; - + @Inject private Event startContainerEvent; - + private static final String AUTH_SERVER_CONTAINER_PROPERTY = "auth.server.container"; private static final String AUTH_SERVER_CONTAINER_DEFAULT = "auth-server-undertow"; - + private static final String MIGRATED_AUTH_SERVER_CONTAINER_PROPERTY = "migrated.auth.server.container"; - + @Inject @SuiteScoped private InstanceProducer suiteContextProducer; private SuiteContext suiteContext; - + @Inject @ClassScoped private InstanceProducer testContextProducer; - + public static String getAuthServerQualifier() { return System.getProperty(AUTH_SERVER_CONTAINER_PROPERTY, AUTH_SERVER_CONTAINER_DEFAULT); } - + public static String getMigratedAuthServerQualifier() { return System.getProperty(MIGRATED_AUTH_SERVER_CONTAINER_PROPERTY); // == null if migration not enabled } - + public static String getAuthServerContextRoot() { return getAuthServerContextRoot(0); } - + public static String getAuthServerContextRoot(int clusterPortOffset) { int httpPort = Integer.parseInt(System.getProperty("auth.server.http.port")); // property must be set int httpsPort = Integer.parseInt(System.getProperty("auth.server.https.port")); // property must be set boolean sslRequired = Boolean.parseBoolean(System.getProperty("auth.server.ssl.required")); - + return sslRequired ? "https://localhost:" + (httpsPort + clusterPortOffset) : "http://localhost:" + (httpPort + clusterPortOffset); } - + public void initializeSuiteContext(@Observes(precedence = 2) BeforeSuite event) { - suiteContext = new SuiteContext(new ArrayList<>(containerRegistry.get().getContainers())); - + + Set containers = new LinkedHashSet<>(); + for (Container c : containerRegistry.get().getContainers()) { + containers.add(new ContainerInfo(c)); + } + + suiteContext = new SuiteContext(containers); + String authServerQualifier = getAuthServerQualifier(); String migratedAuthServerQualifier = getMigratedAuthServerQualifier(); // init authServerInfo and authServerBackendsInfo if (authServerQualifier.startsWith("auth-server-")) { - + boolean authServerCluster = authServerQualifier.endsWith("-cluster"); - + String authServerType = authServerQualifier.replaceAll("^auth-server-", "").replaceAll("-cluster$", ""); String authServerFrontend = authServerCluster ? "auth-server-" + authServerType + "-balancer" // in cluster mode the load-balancer container serves as auth server frontend : authServerQualifier; // single-node mode String authServerBackend = "auth-server-" + authServerType + "-backend"; int backends = 0; - for (Container container : suiteContext.getArquillianContainers()) { + for (ContainerInfo container : suiteContext.getContainers()) { // frontend - if (container.getContainerConfiguration().getContainerName().equals(authServerFrontend)) { - suiteContext.setAuthServerInfo(initializeAuthServerInfo(container)); + if (container.getQualifier().equals(authServerFrontend)) { + updateWithAuthServerInfo(container); + suiteContext.setAuthServerInfo(container); } // backends - if (container.getContainerConfiguration().getContainerName().startsWith(authServerBackend)) { - suiteContext.getAuthServerBackendsInfo().add(initializeAuthServerInfo(container, ++backends)); + if (container.getQualifier().startsWith(authServerBackend)) { + updateWithAuthServerInfo(container, ++backends); + suiteContext.getAuthServerBackendsInfo().add(container); } } @@ -127,18 +136,19 @@ public class AuthServerTestEnricher { if (authServerCluster && !suiteContext.getAuthServerBackendsInfo().isEmpty()) { throw new RuntimeException(String.format("No cluster backend nodes activated. Containers matching '%sN' need to be enabled in arquillian.xml.", authServerBackend)); } - + } else { throw new IllegalArgumentException(String.format("Value of %s should start with 'auth-server-' prefix.", AUTH_SERVER_CONTAINER_PROPERTY)); } - + if (migratedAuthServerQualifier != null) { // init migratedAuthServerInfo if (migratedAuthServerQualifier.startsWith("migrated-auth-server-")) { - for (Container container : suiteContext.getArquillianContainers()) { + for (ContainerInfo container : suiteContext.getContainers()) { // migrated auth server - if (container.getContainerConfiguration().getContainerName().equals(migratedAuthServerQualifier)) { - suiteContext.setMigratedAuthServerInfo(initializeAuthServerInfo(container)); + if (container.getQualifier().equals(migratedAuthServerQualifier)) { + updateWithAuthServerInfo(container); + suiteContext.setMigratedAuthServerInfo(container); } } } else { @@ -150,22 +160,16 @@ public class AuthServerTestEnricher { + "A container matching '%s' needs to be enabled in arquillian.xml.", migratedAuthServerQualifier)); } } - + suiteContextProducer.set(suiteContext); log.info("\n\n" + suiteContext); } - - public void initializeTestContext(@Observes(precedence = 1) BeforeClass event) { - TestContext testContext = new TestContext(suiteContext, event.getTestClass().getJavaClass()); - testContextProducer.set(testContext); + + private ContainerInfo updateWithAuthServerInfo(ContainerInfo authServerInfo) { + return updateWithAuthServerInfo(authServerInfo, 0); } - - private ContainerInfo initializeAuthServerInfo(Container authServerContainer) { - return initializeAuthServerInfo(authServerContainer, 0); - } - - private ContainerInfo initializeAuthServerInfo(Container authServerContainer, int clusterPortOffset) { - ContainerInfo authServerInfo = new ContainerInfo(authServerContainer); + + private ContainerInfo updateWithAuthServerInfo(ContainerInfo authServerInfo, int clusterPortOffset) { try { authServerInfo.setContextRoot(new URL(getAuthServerContextRoot(clusterPortOffset))); } catch (MalformedURLException ex) { @@ -173,20 +177,20 @@ public class AuthServerTestEnricher { } return authServerInfo; } - + public void startMigratedContainer(@Observes(precedence = 2) StartSuiteContainers event) { if (suiteContext.isAuthServerMigrationEnabled()) { log.info("\n\n### Starting keycloak " + System.getProperty("version", "- previous") + " ###\n"); startContainerEvent.fire(new StartContainer(suiteContext.getMigratedAuthServerInfo().getArquillianContainer())); } } - + public void stopMigratedContainer(@Observes(precedence = 1) StartSuiteContainers event) { if (suiteContext.isAuthServerMigrationEnabled()) { containerController.get().stop(suiteContext.getAuthServerInfo().getQualifier()); } } - + public void checkServerLogs(@Observes(precedence = -1) BeforeSuite event) throws IOException, InterruptedException { boolean checkLog = System.getProperty("auth.server.log.check", "true").equals("true"); if (checkLog && suiteContext.getAuthServerInfo().isJBossBased()) { @@ -194,5 +198,10 @@ public class AuthServerTestEnricher { LogChecker.checkJBossServerLog(jbossHomePath); } } - + + public void initializeTestContext(@Observes(precedence = 2) BeforeClass event) { + TestContext testContext = new TestContext(suiteContext, event.getTestClass().getJavaClass()); + testContextProducer.set(testContext); + } + } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainerInfo.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainerInfo.java index 68ae059869..a6bcdc5841 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainerInfo.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainerInfo.java @@ -2,6 +2,7 @@ package org.keycloak.testsuite.arquillian; import java.net.URL; import java.util.Map; +import java.util.Objects; import org.jboss.arquillian.container.spi.Container; /** @@ -12,6 +13,7 @@ public class ContainerInfo { private URL contextRoot; private Container arquillianContainer; + private boolean adapterLibsInstalled; public ContainerInfo(Container arquillianContainer) { if (arquillianContainer == null) { @@ -41,15 +43,15 @@ public class ContainerInfo { } public boolean isAS7() { - return getQualifier().contains("as7"); + return getQualifier().toLowerCase().contains("as7"); } public boolean isWildfly() { - return getQualifier().contains("Wildfly"); + return getQualifier().toLowerCase().contains("wildfly"); } public boolean isEAP() { - return getQualifier().contains("eap"); + return getQualifier().toLowerCase().contains("eap"); } public boolean isJBossBased() { @@ -61,4 +63,33 @@ public class ContainerInfo { return getQualifier(); } + public boolean isAdapterLibsInstalled() { + return adapterLibsInstalled; + } + + public void setAdapterLibsInstalled(boolean adapterLibsInstalled) { + this.adapterLibsInstalled = adapterLibsInstalled; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 97 * hash + Objects.hashCode(this.arquillianContainer); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final ContainerInfo other = (ContainerInfo) obj; + return Objects.equals( + this.arquillianContainer.getContainerConfiguration().getContainerName(), + other.arquillianContainer.getContainerConfiguration().getContainerName()); + } + } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/SuiteContext.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/SuiteContext.java index cf58916821..c4bd23b45a 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/SuiteContext.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/SuiteContext.java @@ -20,7 +20,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import org.jboss.arquillian.container.spi.Container; +import java.util.Set; import static org.keycloak.testsuite.util.MailServerConfiguration.*; /** @@ -29,7 +29,7 @@ import static org.keycloak.testsuite.util.MailServerConfiguration.*; */ public final class SuiteContext { - private final List arquillianContainers; + private final Set container; private ContainerInfo authServerInfo; private final List authServerBackendsInfo = new ArrayList<>(); @@ -39,8 +39,8 @@ public final class SuiteContext { private boolean adminPasswordUpdated; private final Map smtpServer = new HashMap<>(); - public SuiteContext(List arquillianContainers) { - this.arquillianContainers = arquillianContainers; + public SuiteContext(Set arquillianContainers) { + this.container = arquillianContainers; this.adminPasswordUpdated = false; smtpServer.put("from", FROM); smtpServer.put("host", HOST); @@ -87,8 +87,8 @@ public final class SuiteContext { return migratedAuthServerInfo != null; } - public List getArquillianContainers() { - return arquillianContainers; + public Set getContainers() { + return container; } @Override diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java index 656df2fe2c..a9ed805c3a 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java @@ -25,7 +25,6 @@ import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.testsuite.AbstractAuthTest; import org.keycloak.testsuite.adapter.page.AppServerContextRoot; -import org.keycloak.testsuite.arquillian.AuthServerTestEnricher; import org.keycloak.testsuite.arquillian.annotation.AppServerContainer; import java.io.IOException; diff --git a/testsuite/integration-arquillian/tests/other/adapters/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/pom.xml index 8b09d913f8..132b8f6346 100644 --- a/testsuite/integration-arquillian/tests/other/adapters/pom.xml +++ b/testsuite/integration-arquillian/tests/other/adapters/pom.xml @@ -286,13 +286,6 @@ - - auth-server-wildfly - - wildfly-relative - - - app-server-eap6 @@ -311,6 +304,12 @@ wildfly + + app-server-wildfly-relative + + wildfly-relative + + app-server-wildfly8 diff --git a/testsuite/integration-arquillian/tests/other/adapters/wildfly-relative/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/wildfly-relative/pom.xml index e705fec69e..89aabe5a86 100644 --- a/testsuite/integration-arquillian/tests/other/adapters/wildfly-relative/pom.xml +++ b/testsuite/integration-arquillian/tests/other/adapters/wildfly-relative/pom.xml @@ -1,20 +1,20 @@ +~ Copyright 2016 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. +--> @@ -54,7 +54,39 @@ + + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + enforce-auth-server-wildfly-profile + + enforce + + + + + auth-server-wildfly + + + + + + + + + + + + + auth-server-wildfly + + + adapter-libs-bundled From 191d03f5f39e6f7a69233f27d0c7a714f7c4930b Mon Sep 17 00:00:00 2001 From: Tomas Kyjovsky Date: Fri, 5 Feb 2016 01:29:53 +0100 Subject: [PATCH 3/5] minor edits --- .../arquillian/AppServerTestEnricher.java | 2 +- .../DeploymentArchiveProcessor.java | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AppServerTestEnricher.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AppServerTestEnricher.java index 47cad7d25f..9289593232 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AppServerTestEnricher.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AppServerTestEnricher.java @@ -106,7 +106,7 @@ public class AppServerTestEnricher { } public void installAdapterLibs(@Observes BeforeDeploy event) { - log.info("BEFORE DEPLOY"); + log.debug("BEFORE DEPLOY - INSTALL ADAPTER LIBS"); if (testContext.isAdapterTest()) { // install adapter libs on JBoss-based container via CLI if (testContext.getAppServerInfo().isJBossBased()) { diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java index da482a8627..e4a8ab20ec 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java @@ -70,7 +70,7 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor { log.info("Processing archive " + archive.getName()); // if (isAdapterTest(testClass)) { modifyAdapterConfigs(archive, testClass); - attachKeycloakLibs(archive, testClass); + attachAdapterLibs(archive, testClass); modifyWebXml(archive, testClass); // } else { // log.info(testClass.getJavaClass().getSimpleName() + " is not an AdapterTest"); @@ -93,21 +93,21 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor { protected void modifyAdapterConfig(Archive archive, String adapterConfigPath, boolean relative) { if (archive.contains(adapterConfigPath)) { log.info("Modifying adapter config " + adapterConfigPath + " in " + archive.getName()); - if (adapterConfigPath.equals(SAML_ADAPTER_CONFIG_PATH)) { + if (adapterConfigPath.equals(SAML_ADAPTER_CONFIG_PATH)) { // SAML adapter config log.info("Modyfying saml adapter config in " + archive.getName()); Document doc = loadXML(archive.get("WEB-INF/keycloak-saml.xml").getAsset().openStream()); if (authServerSslRequired) { - modifyDocElementAttribute(doc, "SingleSignOnService", "bindingUrl", "8080", System.getProperty("auth.server.https.port", null)); + modifyDocElementAttribute(doc, "SingleSignOnService", "bindingUrl", "8080", System.getProperty("auth.server.https.port")); modifyDocElementAttribute(doc, "SingleSignOnService", "bindingUrl", "http", "https"); - modifyDocElementAttribute(doc, "SingleLogoutService", "postBindingUrl", "8080", System.getProperty("auth.server.https.port", null)); + modifyDocElementAttribute(doc, "SingleLogoutService", "postBindingUrl", "8080", System.getProperty("auth.server.https.port")); modifyDocElementAttribute(doc, "SingleLogoutService", "postBindingUrl", "http", "https"); - modifyDocElementAttribute(doc, "SingleLogoutService", "redirectBindingUrl", "8080", System.getProperty("auth.server.https.port", null)); + modifyDocElementAttribute(doc, "SingleLogoutService", "redirectBindingUrl", "8080", System.getProperty("auth.server.https.port")); modifyDocElementAttribute(doc, "SingleLogoutService", "redirectBindingUrl", "http", "https"); } else { - modifyDocElementAttribute(doc, "SingleSignOnService", "bindingUrl", "8080", System.getProperty("auth.server.http.port", null)); - modifyDocElementAttribute(doc, "SingleLogoutService", "postBindingUrl", "8080", System.getProperty("auth.server.http.port", null)); - modifyDocElementAttribute(doc, "SingleLogoutService", "redirectBindingUrl", "8080", System.getProperty("auth.server.http.port", null)); + modifyDocElementAttribute(doc, "SingleSignOnService", "bindingUrl", "8080", System.getProperty("auth.server.http.port")); + modifyDocElementAttribute(doc, "SingleLogoutService", "postBindingUrl", "8080", System.getProperty("auth.server.http.port")); + modifyDocElementAttribute(doc, "SingleLogoutService", "redirectBindingUrl", "8080", System.getProperty("auth.server.http.port")); } try { @@ -116,7 +116,7 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor { log.error("Can't transform document to String"); throw new RuntimeException(e); } - } else { + } else { // OIDC adapter config try { BaseAdapterConfig adapterConfig = loadJson(archive.get(adapterConfigPath) .getAsset().openStream(), BaseAdapterConfig.class); @@ -144,7 +144,7 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor { } } - protected void attachKeycloakLibs(Archive archive, TestClass testClass) { + protected void attachAdapterLibs(Archive archive, TestClass testClass) { AdapterLibsMode adapterType = AdapterLibsMode.getByType(System.getProperty("adapter.libs.mode", AdapterLibsMode.PROVIDED.getType())); log.info("Adapter type: " + adapterType); From 585f1035f9451b5f72236805bcc43909f43160c9 Mon Sep 17 00:00:00 2001 From: Tomas Kyjovsky Date: Fri, 5 Feb 2016 03:54:22 +0100 Subject: [PATCH 4/5] Updated Arquillian testsuite README. --- testsuite/integration-arquillian/README.md | 192 +++++++++++++----- .../integration-arquillian/README_old.md | 189 ----------------- .../base/src/test/resources/arquillian.xml | 7 + 3 files changed, 150 insertions(+), 238 deletions(-) delete mode 100644 testsuite/integration-arquillian/README_old.md diff --git a/testsuite/integration-arquillian/README.md b/testsuite/integration-arquillian/README.md index 7620d980f4..36a8252533 100644 --- a/testsuite/integration-arquillian/README.md +++ b/testsuite/integration-arquillian/README.md @@ -1,61 +1,155 @@ -# Keycloak Integration Testsuite with Arquillian +# Keycloak Arquillian Integration Testsuite -## Structure +## Container Lifecycles + +### Keycloak Auth Server + +There is only one instance of Keycloak server running during a single test run. +It is automatically started by Arquillian on the `BeforeSuite` event and stopped `AfterSuite`. + +The type of container can be determined by property `-Dauth.server.container`. Default value is `auth-server-undertow`, +other options are: `auth-server-wildfly` and `auth-server-eap7`. The values correspond to Arquillian *container qualifiers* in `arquillian.xml` config file. + +**Note 1:** For the non-default options it's necessary to build a corresponding server module prior to running any of the test modules. +This can be done by building the server module directly (from `servers/wildfly`/`servers/eap7`), +or by activating `auth-server-wildfly`/`auth-server-eap7` profile when building from the top level module. +(The profiles will also set the proper value of the `auth.server.container` property.) + +**Note 2:** Most server-side configurations are done during the build of the server module +and included in the output artifact - which is then consumed by the test modules( if a corresponding profile is activated). +To reflect a change in server config in the test (e.g. a datasource) it's necessary to rebuild the server module after each change. + +### Migration + +Migration tests can be enabled by setting `-Dmigrated.auth.server.container` property or activating a corresponding profile. +When enabled, the `AuthServerTestEnricher` class will start/stop the selected *migrated* instance +even **before** the *current* auth server instance is started. + +### App Servers + +Lifecycle of application server is always tied to a particular TestClass. + +Each *adapter* test class is annotated by `@AppServerContainer("app-server-*")` annotation +that links it to a particular Arquillian container in `arquillian.xml`. +The `AppServerTestEnricher` then ensures the server is started before and stopped after all tests methods in the class. +In case the `@AppServerContainer` annotation has no value it's assumed that the application container +is the same as the auth server container (a relative adapter test scenario). + +Adapter tests are separated into submodules because different app containers require different configurations +(installation of adapter libs, etc.). +Container entries of app servers are not present in the main `arquillian.xml` in the `base` module. +Each adapter submodule adds it's own entry before it runs the tests. + +## SuiteContext and TestContext + +These objects are injected into `AbstractKeycloakTest` class so they can be used everywhere. +They can be used to get information about the tested containers, and to store information that won't survive across test classes or test methods. +(Arquillian creates a new instance of test class for each test method run, so all data in the fields is always lost.) + +## REST Testing + +The `AbstractKeycloakTest` has an initialized instance of AdminClient. Subclasses can use it to access any REST subresources. + +## UI Testing + +PageObjects can be injected to tests by `@Page` annotation. + +The base class for all page objects is `AbstractPage`. + +The default browser for UI testing is `phantomjs` which is used for fast "headless" testing. +Other browsers can be selected with the `-Dbrowser` property, for example `firefox`. +See *Arquillian Graphene* documentation for more details. + + +## Test Modules + +### Base Testsuite + +The base testsuite contains custom Arquillian extensions and most functional tests. +The other test modules depend on this module. + +### Admin Console UI Tests + +Tests for Keycloak Admin Console are located in a separate module `tests/other/console` +and are **disabled** by default. Can be enabled by `-Pconsole-ui-tests`. + +### Adapter Tests + +Adapter tests are located in submodules of the `tests/other/adapters` module. + +They are **disabled** by default; they can be enabled by corresponding profiles. +Multiple profiles can be enabled for a single test execution. + +#### Types of adapter tests + +1. Using *custom test servlets* +2. Using *example demo apps* from `keycloak/examples` modules. + +#### Relative vs Non-relative scenario + +The test suite can handle both types. +It automatically modifies imported test realms and deployments' adapter configs based on scenario type. + +| Scenario | Description | Realm config (server side) | Adapter config (client side) | +| --- | --- | --- | --- | +| **Relative** | auth server == app server | client `baseUrl`, `adminUrl` and `redirect-uris` can be relative | `auth-server-url` can be relative | +| **Non-relative** | auth server != app server | client `baseUrl`, `adminUrl` and `redirect-uris` need to include FQDN of the app server | `auth-server-url` needs to include FQDN of the auth server| + + + +#### Adapter Libs Mode + +1. **Provided** - By container, e.g. as a subsystem. **Default.** +2. **Bundled** - In the deployed war in `/WEB-INF/libs`. Enable with `-Dadapter.libs.bundled`. *Wildfly only*. + +#### Adapter Config Mode + +1. ~~**Provided** - In `standalone.xml` using `secure-deployment`. *Wildfly only.*~~ WIP +2. **Bundled** - In the deployed war in `/WEB-INF/keycloak.json`. **Default.** + + +## Maven Modules Structure ``` integration-arquillian │ -├──servers (submodules enabled via profiles) -│ ├──wildfly -│ └──eap6 +├──servers +│ ├──wildfly (activated by -Pauth-server-wildfly) +│ └──eap7 (activated by -Pauth-server-eap7) │ -└──tests - ├──base - └──adapters (submodules enabled via profiles, all depend on base) - ├──wildfly - ├──wildfly-relative (needs servers/wildfly) - ├──wildfly8 - ├──as7 - ├──tomcat - └──karaf - +└──tests (common settings for all test modules) + ├──base (custom ARQ extensions + base functional tests) + └──other (common settings for all modules dependent on base) + │ + ├──adapters (common settings for all adapter submodules) + │ ├──wildfly (activated by -Papp-server-wildfly) + │ ├──wildfly-relative (activated by -Papp-server-wildfly-relative,auth-server-wildfly) + │ ├──... + │ ├──tomcat (activated by -Papp-server-tomcat) + │ └──karaf (activated by -Papp-server-karaf) + │ + ├──console (activated by -Pconsole-ui-tests) + ├──mod_auth_mellon (activated by -Pmod_auth_mellon) + └──... ``` -## General Concepts +## Custom Arquillian Extensions -The testsuite supports **multiple server runtimes** for the Keycloak server. -The **default is Undertow** which is the fastest and easiest option, and runs in the same JVM as the tests. +Custom extensions are registered in `META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension`. -Other options are **Wildfly 9** and **EAP 6**. These have some additional requirements and limitations: -1. The selected server module must be built before any tests can be run. -All server-side configuration is done during this build (e.g. datasource configuration). -Once server artifact is built the tests modules can unpack it via `maven-dependency-plugin` into their working directory before running. -2. Before the selected server module can be built the `keycloak/distribution` module also needs to be built. +### MultipleContainersExtension + * Replaces Arquillian's default container handling. + * Allows to manage multiple container instances of different types within a single test run. + * Allows to skip loading disabled containers based on `enabled` config property in `arquillian.xml`. -### Server Runtimes +### KeycloakArquillianExtension + * `AuthServerTestEnricher` - Handles lifecycle of auth server and migrated auth server. + * `AppServerTestEnricher` - Handles lifecycles of app servers. + * `CustomUndertowContainer` - Custom container controller for JAX-RS-enabled Undertow with Keycloak Server. + * `DeploymentArchiveProcessor` - Modifies adapter configs before test apps are deployed. + * `DeploymentTargetModifier` - Ensures all test app deployments are targeted at app server containers. + * `URLProvider` - Fixes URLs injected by Arquillian Graphene which contain value `127.0.0.1` instead of required `localhost`. + +### CustomKarafContainerExtension -TODO: explain why separate module, list config options, note on migration modules - -### Base Testsuite - -login flows + account management - -admin ui - -abstract adapter tests - -### Adapter Tests - -test servlets: demo, session - -examples - -## Running the Tests - -### Undertow - -### Wildfly or EAP 6 - -### Adapters - -### Supported Browsers \ No newline at end of file +Extension for executing karaf commands after container is started. Used for installation of bundles (test apps and adapter libs). \ No newline at end of file diff --git a/testsuite/integration-arquillian/README_old.md b/testsuite/integration-arquillian/README_old.md deleted file mode 100644 index 76357ce984..0000000000 --- a/testsuite/integration-arquillian/README_old.md +++ /dev/null @@ -1,189 +0,0 @@ -# Keycloak Integration Testsuite with Arquillian - -*OUT OF DATE - NEEDS REWRITE* - -## Usage - -Running the tests: `mvn test` or `mvn clean test` - -## Test suite - -### Selecting container for Keycloak Server - -The testsuite requires a container for Keycloak Server to be selected. -This container is used by all tests in the suite during a single test execution. - -*By default* the tests run with server on embedded *Undertow*. -A different container can be selected with profile, e.g. `-Pauth-server-wildfly`. - -### Containers Supported for Keycloak Server - -| Container | Arquillian Qualifier | Maven | Dependencies | -| --- | --- | --- | --- | -| **Undertow** | `auth-server-undertow` | **default** | `undertow-core`, `resteasy-undertow` | -| **Wildfly 9** | `auth-server-wildfly` | `-Pauth-server-wildfly` | `keycloak-server-dist` or `wildfly-dist`+`keycloak-server-overlay` | -| **EAP 6.4** | `auth-server-eap6` | `-Pauth-server-eap6` | `keycloak-server-dist` or `eap6-dist`+`keycloak-server-overlay` | - -See the relevant container definitions in `arquillian.xml` located in the **test resources** folder. - -### Test Class Hierarchy -``` -AbstractKeycloakTest -├── AbstractAdminConsoleTest -└── AbstractAdapterTest -``` - -### AbstractKeycloakTest - -Handles test realms. Provides Admin Client for REST operations. - -* **@BeforeClass** - 1. Updates the admin password to enable the admin user. -* **@Before** - 1. Initiates admin client - 2. Imports test realms. (Loading test realms is overriden in subclasses.) -* **@After** - 1. Removes test realms. - 2. Closes admin client. - -### ContainersTestEnricher - -Manages *container lifecycles*. - -`ContainersTestEnricher` is a custom Arquillian observer that handles lifecycles of auth server and app server containers for each test class. -Containers are started during `@BeforeClass` and shut down during `@AfterClass` event. - -*Optionally* each test class can be annotated with `@AuthServerContainer("qualifier")` and `@AppServerConatiner("qualifier")` annotations -to indicate containers required for the test. - -* In case `@AuthServerContainer` is not present the *auth server qualifier* is loaded from `auth.server.container` property. -* In case `@AppServerContainer` is not present or it's value is the same as *auth server qualifier*, the app server isn't started for the test class. - -## Admin Console Tests - -Tests for admin console are located in `org/keycloak/testsuite/console`. -Related non-test classes are located on the same path in the **main sources**. - -Admin console tests are **ENABLED by default**. They can be disabled by `-P no-console`. - - -## Adapter Tests - -Adapter tests are located in `org/keycloak/testsuite/adapter`. -Related non-test classes can be found on the same path in the **main sources**. - -Adapter tests are **DISABLED by default**. They can be enabled by profiles. -Multiple profiles can be enabled for a single test execution. - -*Note:* When testing adapter with multiple containers in a single run it is better -to use the `--fail-at-end` (`-fae`) strategy instead of the default `--fail-fast` one. -This will allow Maven to continue building other modules even if some of them have test failures. - -### Containers Supported for Adapter Tests - -| Container | Arquillian Qualifier | Maven | Dependencies | -| --- | --- | --- | --- | -| **Wildfly 9** Relative | `auth-server-wildfly` | `-Pauth-server-wildfly` | `keycloak-server-dist` or `wildfly-dist`+`keycloak-server-overlay`, `keycloak-adapter-dist-wf9` | -| **Wildfly 9** | `app-server-wildfly` | `-Papp-server-wildfly` | `wildfly-dist`, `keycloak-adapter-dist-wf9` | -| **Wildfly 8** | `app-server-wildfly` | `-Papp-server-wildfly8` | `wildfly-dist:8.2.1.Final`, `keycloak-adapter-dist-wf8` | -| **JBoss AS 7** | `app-server-as7` | `-Papp-server-as7` | `jboss-as-dist`, `keycloak-adapter-dist-as7` | -| **Tomcat 8** | `app-server-tomcat` | `-Papp-server-tomcat` | `tomcat`, `keycloak-tomcat8-adapter-dist` | -| **Karaf 3** | `app-server-karaf` | `-Papp-server-karaf` | `apache-camel`, `apache-cxf`, `keycloak-osgi-features`, `keycloak-fuse-example-features` | - -See the relevant container definitions in `tests/adapter//src/main/xslt/arquillian.xsl`. - -***Important:*** Arquillian cannot load multiple controllers for JBossAS/Wildfly containers in a single run (because same class name) -but a different controller is required for JBossAS7/EAP6 than for WF8/9. Because of this: - - - Adapter tests for *Wildfly 8/9* cannot be run against server on *EAP 6*. `-Papp-server-wildfly*` ⇒ `!auth-server-eap6` - - Adapter tests for *JBossAS 7* can only be run against server on *EAP 6*. `-Papp-server-as7,auth-server-eap6` - -### Adapter Test Types - -1. Using **test servlets**. -2. Using **example/demo wars**. - -``` -AbstractKeycloakTest -└── AbstractAdapterTest - ├── AbstractServletsAdapterTest - | ├── Relative… - | ├── Wildfly… - | ├── Tomcat… - | … - └── AbstractExampleAdapterTest - ├── AbstractDemoExampleAdapterTest - | ├── Relative… - | ├── Wildfly… - | ├── Tomcat… - | … - ├── AbstractBasicAuthExampleAdapterTest - | ├── Relative… - | ├── Wildfly… - | ├── Tomcat… - | … - … -``` - -### Relative vs Non-relative scenario - -The test suite can handle both types. -It automatically modifies imported test realms and deployments' adapter configs based on scenario type. - -| Scenario | Description | Realm config (server side) | Adapter config (client side) | -| --- | --- | --- | --- | -| **Relative** | Both Keycloak Server and test apps running in the same container. | client `baseUrl`, `adminUrl` and `redirect-uris` can be relative | `auth-server-url` can be relative | -| **Non-relative** | Test apps run in a different container than Keycloak Server. | client `baseUrl`, `adminUrl` and `redirect-uris` need to include FQDN of the app server | `auth-server-url` needs to include FQDN of the auth server| - -### Adapter Libraries Mode - -1. **Provided.** By container, e.g. as a subsystem. *Default.* -2. **Bundled.** In the deployed war in `/WEB-INF/libs`. Enable with `-Dadapter.libs.bundled`. *Wildfly only*. - -### Adapter Config Mode - -1. ~~**Provided.** In `standalone.xml` using `secure-deployment`. *Wildfly only.*~~ WIP -2. **Bundled.** In the deployed war in `/WEB-INF/keycloak.json`. *Default.* - -### Adapters Test Coverage - -| Module | Coverage | Supported Containers | -| --- | --- | --- | -| ***Test Servlets*** | Good | All | -| **Demo** | Minimal, WIP | `auth-server-wildfly` (relative) | -| **Admin Client** | | -| **Cordova** | | -| **CORS** | | -| **JS Console** | Good | `auth-server-wildfly` (relative) | -| **Providers** | | -| Themes | | -| Multitenancy | WIP | | -| **Basic Auth** | Good | All | -| **Fuse** | Good | `app-server-karaf` | -| SAML | | -| LDAP | | -| Kerberos | | - -## Supported Browsers - -| Browser | Maven | -| --- | --- | -| **PhantomJS** | `-Dbrowser=phantomjs` **default** | -| **Firefox** | `-Dbrowser=firefox` | - - -## Custom Arquillian Extensions - -Custom extensions are registered in `META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension`. - -* Multiple containers extension - * Replaces Arquillian's default container handling. - * Allows to manage multiple container instances of different types within a single test run. - * Allows to skip loading disabled containers based on `enabled` config property in `arquillian.xml`. -* Custom extension - * `ContainersTestEnricher` - Handles lifecycles of auth-server and app-server. - * `CustomUndertowContainer` - A custom container controller for JAX-RS-enabled Undertow with Keycloak Server. - * `DeploymentArchiveProcessor` - Modifies adapter config before deployment on app server based on relative/non-relative scenario. - * `URLProvider` - Fixes URLs injected by Arquillian which contain 127.0.0.1 instead of localhost. - * `JiraTestExecutionDecider` - Skipping tests for unresolved JIRAs. - 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 57e1692dcd..555f3ce35a 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml +++ b/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml @@ -181,5 +181,12 @@ + From dfeb35b5e6edc2fcffdca136fdf3145f69c858cd Mon Sep 17 00:00:00 2001 From: Tomas Kyjovsky Date: Fri, 5 Feb 2016 04:16:01 +0100 Subject: [PATCH 5/5] Updated Arquillian testsuite README / UI Testing. --- testsuite/integration-arquillian/README.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/testsuite/integration-arquillian/README.md b/testsuite/integration-arquillian/README.md index 36a8252533..5f7f831649 100644 --- a/testsuite/integration-arquillian/README.md +++ b/testsuite/integration-arquillian/README.md @@ -52,13 +52,24 @@ The `AbstractKeycloakTest` has an initialized instance of AdminClient. Subclasse ## UI Testing -PageObjects can be injected to tests by `@Page` annotation. +### Page Objects -The base class for all page objects is `AbstractPage`. +Page Objects are used by tests to access and operate on UI. +They can be injected using annotation `@Page` provided by the *Arquillian Graphene* extension. + +The base class for all page objects used throughout this Arquillian testsuite is `AbstractPage`, and it's subclass `AbstractPageWithInjectedUrl`. + +For the page objects for the *adapter test apps* the URLs are injected automatically by Arquillian depending on actual URL of the deployed app/example. + +For the pages under the `/auth` context the URL is only injected to the `AuthServerContextRoot` page object, +and the URL hierarchy is modeled by the class inheritance hierarchy (subclasses/extending of `AuthServerContextRoot`). + + +### Browsers The default browser for UI testing is `phantomjs` which is used for fast "headless" testing. Other browsers can be selected with the `-Dbrowser` property, for example `firefox`. -See *Arquillian Graphene* documentation for more details. +See Arquillian Graphene documentation for more details. ## Test Modules