KEYCLOAK-1678 Reorganized containers handling. (WIP: adapter-libs installation via CLI doesn't work)

This commit is contained in:
Tomas Kyjovsky 2016-02-04 20:24:58 +01:00
parent eae52a563c
commit 3a51b3530d
37 changed files with 892 additions and 581 deletions

View file

@ -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<TestContext> testContextProducer;
private TestContext testContext;
@Inject
private Instance<ContainerController> containerController;
public static String getAppServerQualifier(Class testClass) {
Class<? extends AuthServerTestEnricher> 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<? extends AuthServerTestEnricher> 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");
}
}

View file

@ -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> containerRegistry;
@Inject
private Instance<ContainerController> containerController;
@Inject
private Event<StartContainer> 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<SuiteContext> suiteContextProducer;
private SuiteContext suiteContext;
@Inject
@ClassScoped
private InstanceProducer<TestContext> 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);
}
}
}

View file

@ -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<String, String> 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();
}
}

View file

@ -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> containerController;
@Inject
private Instance<ContainerRegistry> containerRegistry;
@Inject
private Event<StopSuiteContainers> 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> suiteContext;
@Inject
@ClassScoped
private InstanceProducer<TestContext> testContext;
@Inject
@ClassScoped
private InstanceProducer<Keycloak> adminClient;
@Inject
@ClassScoped
private InstanceProducer<OAuthClient> oauthClient;
private ContainerController controller;
private LinkedList<Container> 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<? extends ContainersTestEnricher> 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<? extends ContainersTestEnricher> 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("</").append(type).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");
}
}

View file

@ -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);
}

View file

@ -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

View file

@ -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);

View file

@ -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<Container> arquillianContainers;
private ContainerInfo authServerInfo;
private final List<ContainerInfo> authServerBackendsInfo = new ArrayList<>();
private ContainerInfo migratedAuthServerInfo;
private boolean adminPasswordUpdated;
private final Map<String, String> smtpServer = new HashMap<>();
public SuiteContext() {
public SuiteContext(List<Container> 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<String, String> getSmtpServer() {
return smtpServer;
}
public ContainerInfo getAuthServerInfo() {
return authServerInfo;
}
public void setAuthServerInfo(ContainerInfo authServerInfo) {
this.authServerInfo = authServerInfo;
}
public List<ContainerInfo> 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<Container> getArquillianContainers() {
return arquillianContainers;
}
@Override
public String toString() {
return "SUITE CONTEXT:\n"
+ "Auth server: " + authServerInfo.getQualifier() + "\n"
+(isAuthServerCluster() ? "Auth server cluster: " + getAuthServerBackendsInfo().size() + " nodes+\n" : "");
}
}

View file

@ -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<ContainerInfo> 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<ContainerInfo> 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" : "");
}
}

View file

@ -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> suiteContext;
@Inject
Instance<TestContext> 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();
}
}

View file

@ -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;
// }
}

View file

@ -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();

View file

@ -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 {

View file

@ -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();
// }
}

View file

@ -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> T loadJson(InputStream is, Class<T> 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("</").append(type).append(">");
System.out.println(builder);
}
}

View file

@ -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"));
}
}

View file

@ -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<RealmRepresentation> 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();
}
}

View file

@ -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<RealmRepresentation> testRealms) {
}
@Test
public void testAuthServer() {
log.info("AUTH SERVER should be started.");
assertTrue(controller.isStarted(AuthServerTestEnricher.getAuthServerQualifier()));
}
}

View file

@ -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<RealmRepresentation> testRealms);
public boolean isRelative() {
return ContainersTestEnricher.isRelative(this.getClass());
return testContext.isRelativeAdapterTest();
}
protected void modifyClientRedirectUris(RealmRepresentation realm, String regex, String replacement) {

View file

@ -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

View file

@ -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());

View file

@ -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.
-->
~ 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.
-->
<arquillian xmlns="http://jboss.org/schema/arquillian"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@ -44,80 +44,6 @@
<property name="deploymentExportPath">target/deployments</property>
</engine>
<!-- PREVIOUS VERSIONS KEYCLOAK FOR MIGRATION TESTS -->
<!-- IT HAS TO BE LISTED ABOWE KEYCLOAK AUTH SERVERS -->
<container qualifier="keycloak-1.6.1.Final" mode="suite" >
<configuration>
<property name="enabled">${migration.kc16}</property>
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
<property name="jbossHome">${keycloak.migration.home}</property>
<property name="javaVmArguments">
-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
</property>
<property name="managementPort">${auth.server.management.port}</property>
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
</configuration>
</container>
<container qualifier="keycloak-1.5.1.Final" mode="suite" >
<configuration>
<property name="enabled">${migration.kc15}</property>
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
<property name="jbossHome">${keycloak.migration.home}</property>
<property name="javaVmArguments">
-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
</property>
<property name="managementPort">${auth.server.management.port}</property>
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
</configuration>
</container>
<container qualifier="keycloak-1.4.0.Final" mode="suite" >
<configuration>
<property name="enabled">${migration.kc14}</property>
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
<property name="jbossHome">${keycloak.migration.home}</property>
<property name="javaVmArguments">-Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m</property>
<property name="managementPort">${auth.server.management.port}</property>
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
</configuration>
</container>
<container qualifier="keycloak-1.3.1.Final" mode="suite" >
<configuration>
<property name="enabled">${migration.kc13}</property>
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
<property name="jbossHome">${keycloak.migration.home}</property>
<property name="javaVmArguments">-Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m</property>
<property name="managementPort">${auth.server.management.port}</property>
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
</configuration>
</container>
<container qualifier="keycloak-1.2.0.Final" mode="suite" >
<configuration>
<property name="enabled">${migration.kc12}</property>
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
<property name="jbossHome">${keycloak.migration.home}</property>
<property name="javaVmArguments">-Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m</property>
<property name="managementPort">${auth.server.management.port}</property>
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
</configuration>
</container>
<!-- KEYCLOAK AUTH SERVERS -->
<container qualifier="auth-server-undertow" mode="suite" >
@ -140,6 +66,37 @@
</configuration>
</container>
<group qualifier="auth-server-wildfly-cluster">
<container qualifier="auth-server-wildfly-balancer" mode="suite" >
<configuration>
<property name="enabled">${auth.server.wildfly.cluster}</property>
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
<property name="jbossHome">${wildfly.home}</property>
<property name="javaVmArguments">
-Djboss.socket.binding.port-offset=${auth.server.port.offset}
-Xms64m -Xmx512m -XX:MaxPermSize=256m
${adapter.test.props}
</property>
<property name="managementPort">${auth.server.management.port}</property>
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
</configuration>
</container>
<container qualifier="auth-server-wildfly-backend1" mode="manual" >
<configuration>
<property name="enabled">${auth.server.wildfly.cluster}</property>
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
<property name="jbossHome">${keycloak.backend1.home}</property>
<property name="javaVmArguments">
-Djboss.socket.binding.port-offset=${auth.server.backend1.port.offset}
-Xms64m -Xmx512m -XX:MaxPermSize=256m
${adapter.test.props}
</property>
<property name="managementPort">${auth.server.backend1.management.port}</property>
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
</configuration>
</container>
</group>
<container qualifier="auth-server-eap7" mode="suite" >
<configuration>
<property name="enabled">${auth.server.eap7}</property>
@ -150,5 +107,79 @@
<property name="managementPort">${auth.server.management.port}</property>
</configuration>
</container>
<!-- PREVIOUS VERSIONS OF KEYCLOAK FOR MIGRATION TESTS -->
<container qualifier="migrated-auth-server-wildfly_kc16" mode="manual" >
<configuration>
<property name="enabled">${migration.kc16}</property>
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
<property name="jbossHome">${keycloak.migration.home}</property>
<property name="javaVmArguments">
-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
</property>
<property name="managementPort">${auth.server.management.port}</property>
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
</configuration>
</container>
<container qualifier="migrated-auth-server-wildfly_kc15" mode="manual" >
<configuration>
<property name="enabled">${migration.kc15}</property>
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
<property name="jbossHome">${keycloak.migration.home}</property>
<property name="javaVmArguments">
-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
</property>
<property name="managementPort">${auth.server.management.port}</property>
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
</configuration>
</container>
<container qualifier="migrated-auth-server-wildfly_kc14" mode="manual" >
<configuration>
<property name="enabled">${migration.kc14}</property>
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
<property name="jbossHome">${keycloak.migration.home}</property>
<property name="javaVmArguments">-Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m</property>
<property name="managementPort">${auth.server.management.port}</property>
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
</configuration>
</container>
<container qualifier="migrated-auth-server-wildfly_kc13" mode="manual" >
<configuration>
<property name="enabled">${migration.kc13}</property>
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
<property name="jbossHome">${keycloak.migration.home}</property>
<property name="javaVmArguments">-Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m</property>
<property name="managementPort">${auth.server.management.port}</property>
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
</configuration>
</container>
<container qualifier="migrated-auth-server-wildfly_kc12" mode="manual" >
<configuration>
<property name="enabled">${migration.kc12}</property>
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
<property name="jbossHome">${keycloak.migration.home}</property>
<property name="javaVmArguments">-Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m</property>
<property name="managementPort">${auth.server.management.port}</property>
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
</configuration>
</container>
</arquillian>

View file

@ -108,8 +108,6 @@ public class Client extends Clients {
}
public ClientResource clientResource() {
return clientsResource().get(getId());
}
}

View file

@ -126,8 +126,4 @@ public class Clients extends AdminConsoleRealm {
}
}
public ClientsResource clientsResource() {
return realmResource().clients();
}
}

View file

@ -22,9 +22,5 @@ public class ClientRoles extends Client {
public RolesTable roles() {
return table;
}
public RolesResource rolesResource() {
return clientResource().roles();
}
}

View file

@ -92,8 +92,4 @@ public class IdentityProviderSettings extends AdminConsoleRealm {
return rows;
}
public IdentityProvidersResource identityProviders() {
return realmResource().identityProviders();
}
}

View file

@ -35,8 +35,4 @@ public class Roles extends AdminConsoleRealm {
}
public RolesResource rolesResource() {
return realmResource().roles();
}
}

View file

@ -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());
}
}

View file

@ -20,9 +20,5 @@ public class UserRoleMappings extends User {
public UserRoleMappingsForm form() {
return form;
}
public RoleMappingResource roleMappingResource() {
return userResource().roles();
}
}

View file

@ -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();
}
}

View file

@ -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;

View file

@ -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<String> redirectUrisList = new ArrayList<>();
redirectUrisList.addAll(Arrays.asList(redirectUris));
client.setRedirectUris(redirectUrisList);
}
protected static void setExpectedWebOrigins(ClientRepresentation client) {
List<String> 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<String, String> expected, Map<String, String> actual) {
for (String key : expected.keySet()) {
assertEquals("Expected attribute " + key, expected.get(key), actual.get(key));
}
}
protected static Map<String, String> getSAMLAttributes() {
Map<String, String> 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);
}
}

View file

@ -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());
}

View file

@ -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();
}
}

View file

@ -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;

View file

@ -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();
}
}

View file

@ -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);
}
}