From a8bad5b9bbaae0633d5e5a4ee36ac80f3cd6f0ee Mon Sep 17 00:00:00 2001 From: Pedro Igor Date: Mon, 8 Jun 2020 17:57:22 -0300 Subject: [PATCH] [KEYCLOAK-11330] - Quarkus clustering tests --- .../java/org/keycloak/common/util/Retry.java | 2 +- .../integration-arquillian/HOW-TO-RUN.md | 53 +++++++++++++++- .../servers/auth-server/quarkus/assembly.xml | 9 ++- .../servers/auth-server/quarkus/pom.xml | 13 ++++ .../src/main/content/conf/cluster-ha.xml | 62 +++++++++++++++++++ .../conf/{cluster.xml => cluster-local.xml} | 40 ------------ .../src/main/content/conf/keycloak.properties | 5 +- .../KeycloakQuarkusConfiguration.java | 46 ++++++++++++++ ...cloakQuarkusServerDeployableContainer.java | 26 ++++++-- .../cluster/AbstractClusterTest.java | 11 +++- .../AuthenticationSessionClusterTest.java | 4 +- ...henticationSessionFailoverClusterTest.java | 4 +- .../ClientInvalidationClusterTest.java | 31 +++++++--- .../cluster/GroupInvalidationClusterTest.java | 31 +++++++--- .../cluster/RealmInvalidationClusterTest.java | 24 ++++--- .../cluster/RoleInvalidationClusterTest.java | 30 ++++++--- .../base/src/test/resources/arquillian.xml | 45 ++++++++++++++ .../integration-arquillian/tests/pom.xml | 60 ++++++++++++++++++ 18 files changed, 412 insertions(+), 84 deletions(-) create mode 100644 testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/cluster-ha.xml rename testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/{cluster.xml => cluster-local.xml} (62%) diff --git a/common/src/main/java/org/keycloak/common/util/Retry.java b/common/src/main/java/org/keycloak/common/util/Retry.java index 0aca842087..f16766ed58 100644 --- a/common/src/main/java/org/keycloak/common/util/Retry.java +++ b/common/src/main/java/org/keycloak/common/util/Retry.java @@ -131,7 +131,7 @@ public class Retry { while (true) { try { return supplier.get(iteration); - } catch (RuntimeException | AssertionError e) { + } catch (Exception | AssertionError e) { attemptsCount--; iteration++; if (attemptsCount > 0) { diff --git a/testsuite/integration-arquillian/HOW-TO-RUN.md b/testsuite/integration-arquillian/HOW-TO-RUN.md index 81fea9fc10..25666cf3e3 100644 --- a/testsuite/integration-arquillian/HOW-TO-RUN.md +++ b/testsuite/integration-arquillian/HOW-TO-RUN.md @@ -649,6 +649,46 @@ After you build the distribution, you run this command to setup servers and run -Dauth.server.log.check=false \ -Dfrontend.console.output=true \ -Dtest=org.keycloak.testsuite.cluster.**.*Test clean install + +### Cluster tests with Keycloak on Quarkus + +Run tests using the `auth-server-cluster-quarkus` profile: + + mvn -f testsuite/integration-arquillian/tests/base/pom.xml clean install \ + -Pauth-server-cluster-quarkus \ + -Dsession.cache.owners=2 \ + -Dtest=AuthenticationSessionFailoverClusterTest + +--- +**NOTE** + +Right now, tests are using a H2 database. + +To run tests using a different database such as PostgreSQL, add the following properties into the `testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/keycloak.properties` configuration file: + +``` +# HA using PostgreSQL +%ha.datasource.dialect=org.hibernate.dialect.PostgreSQL9Dialect +%ha.datasource.driver = org.postgresql.xa.PGXADataSource +%ha.datasource.url = jdbc:postgresql://localhost/keycloak +%ha.datasource.username = keycloak +%ha.datasource.password = password +``` + +The `ha` profile is automatically set when running clustering tests. + +This is temporary and database configuration should be more integrated with the test suite once we review Quarkus configuration. + +--- + +#### Run cluster tests from IDE on Quarkus + +Activate the following profiles: + +* `quarkus` +* `auth-server-cluster-quarkus` + +Then run any cluster test as usual. ### Cluster tests with Keycloak on embedded undertow @@ -915,13 +955,22 @@ When running the test, add the following arguments to the command line: Java 11 requires some arguments to be passed to JVM. Those can be activated using `-Pjava11-auth-server` and `-Pjava11-app-server` profiles, respectively. -### Running tests using Quarkus distribution +## Running tests using Quarkus distribution + +### Before Everything Make sure you build the project using the `quarkus` profile as follows: mvn -Pdistribution,quarkus clean install + +### Running tests -Then, just run tests using the `auth-server-quarkus` profile: +Run tests using the `auth-server-quarkus` profile: mvn -f testsuite/integration-arquillian/tests/base/pom.xml clean install -Pauth-server-quarkus + +### Debug the Server + +Right now, the server runs in a separate process. To debug the server set `auth.server.debug` system property to `true`. +To configure the debugger port, set the `auth.server.debug.port` system property with any valid port number. Default is `5005`. \ No newline at end of file diff --git a/testsuite/integration-arquillian/servers/auth-server/quarkus/assembly.xml b/testsuite/integration-arquillian/servers/auth-server/quarkus/assembly.xml index 98ca007188..02b9065cad 100644 --- a/testsuite/integration-arquillian/servers/auth-server/quarkus/assembly.xml +++ b/testsuite/integration-arquillian/servers/auth-server/quarkus/assembly.xml @@ -42,5 +42,12 @@ 0755 - + + + src/main/content/conf/cluster-${auth.server.quarkus.config}.xml + /auth-server-quarkus/conf + cluster.xml + true + + diff --git a/testsuite/integration-arquillian/servers/auth-server/quarkus/pom.xml b/testsuite/integration-arquillian/servers/auth-server/quarkus/pom.xml index c945743b81..43313ec1e1 100644 --- a/testsuite/integration-arquillian/servers/auth-server/quarkus/pom.xml +++ b/testsuite/integration-arquillian/servers/auth-server/quarkus/pom.xml @@ -14,6 +14,10 @@ ${project.build.directory}/unpacked/keycloak.x-${project.version} + 2 + 2 + 2 + local @@ -112,4 +116,13 @@ + + + + auth-server-cluster-quarkus + + ha + + + \ No newline at end of file diff --git a/testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/cluster-ha.xml b/testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/cluster-ha.xml new file mode 100644 index 0000000000..dfd58175e8 --- /dev/null +++ b/testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/cluster-ha.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/cluster.xml b/testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/cluster-local.xml similarity index 62% rename from testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/cluster.xml rename to testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/cluster-local.xml index 17347704f9..da2da830df 100644 --- a/testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/cluster.xml +++ b/testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/cluster-local.xml @@ -21,46 +21,6 @@ xsi:schemaLocation="urn:infinispan:config:9.4 http://www.infinispan.org/schemas/infinispan-config-9.4.xsd" xmlns="urn:infinispan:config:9.4"> - - diff --git a/testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/keycloak.properties b/testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/keycloak.properties index ea1c12c638..efae863a92 100644 --- a/testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/keycloak.properties +++ b/testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/keycloak.properties @@ -6,7 +6,7 @@ datasource.jdbc.transactions=xa # H2 datasource.dialect=org.hibernate.dialect.H2Dialect datasource.driver=org.h2.jdbcx.JdbcDataSource -datasource.url = jdbc:h2:file:${keycloak.home.dir}/data/keycloakdb;AUTO_SERVER=TRUE +datasource.url = jdbc:h2:file:${keycloak.home.dir}/data/keycloakdb;AUTO_SERVER=TRUE;DB_CLOSE_DELAY=-1 datasource.username = sa datasource.password = keycloak @@ -14,6 +14,9 @@ datasource.password = keycloak http.ssl.certificate.key-store-file=${keycloak.home.dir}/conf/keycloak.jks http.ssl.certificate.key-store-password=secret +# Proxy +http.proxy-address-forwarding=true + # Truststore Provider truststore.file.file=${keycloak.home.dir}/conf/keycloak.truststore truststore.file.password=secret \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/KeycloakQuarkusConfiguration.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/KeycloakQuarkusConfiguration.java index 849e1f7a3a..8c0cf4377b 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/KeycloakQuarkusConfiguration.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/KeycloakQuarkusConfiguration.java @@ -1,11 +1,16 @@ package org.keycloak.testsuite.arquillian.containers; +import com.fasterxml.jackson.core.type.TypeReference; import org.jboss.arquillian.container.spi.ConfigurationException; import org.jboss.arquillian.container.spi.client.container.ContainerConfiguration; import org.jboss.logging.Logger; +import org.keycloak.util.JsonSerialization; +import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; /** * @author mhajas @@ -20,6 +25,10 @@ public class KeycloakQuarkusConfiguration implements ContainerConfiguration { private int bindHttpsPort = Integer.valueOf(System.getProperty("auth.server.https.port", "8543")); private Path providersPath = Paths.get(System.getProperty("auth.server.home")); private int startupTimeoutInSeconds = 60; + private String route; + private String keycloakConfigPropertyOverrides; + private HashMap keycloakConfigPropertyOverridesMap; + private String profile; @Override public void validate() throws ConfigurationException { @@ -32,6 +41,15 @@ public class KeycloakQuarkusConfiguration implements ContainerConfiguration { setBindHttpsPort(newHttpsPort); log.info("Keycloak will listen for http on port: " + newPort + " and for https on port: " + newHttpsPort); + + if (this.keycloakConfigPropertyOverrides != null) { + try { + TypeReference> typeRef = new TypeReference>() {}; + this.keycloakConfigPropertyOverridesMap = JsonSerialization.sysPropertiesAwareMapper.readValue(this.keycloakConfigPropertyOverrides, typeRef); + } catch (IOException ex) { + throw new ConfigurationException(ex); + } + } } public int getBindHttpPortOffset() { @@ -81,4 +99,32 @@ public class KeycloakQuarkusConfiguration implements ContainerConfiguration { public void setStartupTimeoutInSeconds(int startupTimeoutInSeconds) { this.startupTimeoutInSeconds = startupTimeoutInSeconds; } + + public String getRoute() { + return route; + } + + public void setRoute(String route) { + this.route = route; + } + + public String getProfile() { + return profile; + } + + public void setProfile(String profile) { + this.profile = profile; + } + + public String getKeycloakConfigPropertyOverrides() { + return keycloakConfigPropertyOverrides; + } + + public void setKeycloakConfigPropertyOverrides(String keycloakConfigPropertyOverrides) { + this.keycloakConfigPropertyOverrides = keycloakConfigPropertyOverrides; + } + + public Map getKeycloakConfigPropertyOverridesMap() { + return keycloakConfigPropertyOverridesMap; + } } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/KeycloakQuarkusServerDeployableContainer.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/KeycloakQuarkusServerDeployableContainer.java index 6dfe143699..9d0074586e 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/KeycloakQuarkusServerDeployableContainer.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/KeycloakQuarkusServerDeployableContainer.java @@ -42,7 +42,7 @@ public class KeycloakQuarkusServerDeployableContainer implements DeployableConta private KeycloakQuarkusConfiguration configuration; private Process container; - private AtomicBoolean restart = new AtomicBoolean(); + private static AtomicBoolean restart = new AtomicBoolean(); @Inject private Instance suiteContext; @@ -130,6 +130,12 @@ public class KeycloakQuarkusServerDeployableContainer implements DeployableConta commands.add("-Dquarkus.http.port=" + configuration.getBindHttpPort()); commands.add("-Dquarkus.http.ssl-port=" + configuration.getBindHttpsPort()); + if (configuration.getRoute() != null) { + commands.add("-Djboss.node.name=" + configuration.getRoute()); + } + + commands.add("-Dquarkus.profile=" + System.getProperty("auth.server.quarkus.config", "local")); + return commands.toArray(new String[commands.size()]); } @@ -137,7 +143,7 @@ public class KeycloakQuarkusServerDeployableContainer implements DeployableConta SuiteContext suiteContext = this.suiteContext.get(); //TODO: not sure if the best endpoint but it makes sure that everything is properly initialized. Once we have // support for MP Health this should change - URL contextRoot = new URL(suiteContext.getAuthServerInfo().getContextRoot() + "/auth/realms/master/"); + URL contextRoot = new URL(getBaseUrl(suiteContext) + "/auth/realms/master/"); HttpURLConnection connection; long startTime = System.currentTimeMillis(); @@ -150,7 +156,7 @@ public class KeycloakQuarkusServerDeployableContainer implements DeployableConta try { // wait before checking for opening a new connection Thread.sleep(1000); - if ("https".equals(contextRoot.toURI().getScheme())) { + if ("https".equals(contextRoot.getProtocol())) { HttpsURLConnection httpsConnection = (HttpsURLConnection) (connection = (HttpURLConnection) contextRoot.openConnection()); httpsConnection.setSSLSocketFactory(createInsecureSslSocketFactory()); httpsConnection.setHostnameVerifier(createInsecureHostnameVerifier()); @@ -171,7 +177,19 @@ public class KeycloakQuarkusServerDeployableContainer implements DeployableConta } } - log.infof("Keycloak is ready at %s", this.suiteContext.get().getAuthServerInfo().getContextRoot()); + log.infof("Keycloak is ready at %s", contextRoot); + } + + private URL getBaseUrl(SuiteContext suiteContext) throws MalformedURLException { + URL baseUrl = suiteContext.getAuthServerInfo().getContextRoot(); + + // might be running behind a load balancer + if ("https".equals(baseUrl.getProtocol())) { + baseUrl = new URL(baseUrl.toString().replace(String.valueOf(baseUrl.getPort()), String.valueOf(configuration.getBindHttpsPort()))); + } else { + baseUrl = new URL(baseUrl.toString().replace(String.valueOf(baseUrl.getPort()), String.valueOf(configuration.getBindHttpPort()))); + } + return baseUrl; } private HostnameVerifier createInsecureHostnameVerifier() { diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java index 0feb5b2672..d361a62f40 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractClusterTest.java @@ -61,8 +61,15 @@ public abstract class AbstractClusterTest extends AbstractKeycloakTest { } // Assume that route like "node6" will have corresponding backend container like "auth-server-wildfly-backend6" - protected void setCurrentFailNodeForRoute(String route) { - String routeNumber = route.substring(route.length() - 1); + protected void setCurrentFailNodeForRoute(String nodeName) { + String route = nodeName.substring(nodeName.lastIndexOf('.') + 1); + String routeNumber; + int portSeparator = route.indexOf('-'); + if (portSeparator == -1) { + routeNumber = route.substring(route.length() - 1); + } else { + routeNumber = route.substring(portSeparator - 1, portSeparator); + } currentFailNodeIndex = Integer.parseInt(routeNumber) - 1; } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionClusterTest.java index e1813179e3..bb2b3ae04f 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionClusterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionClusterTest.java @@ -99,7 +99,7 @@ public class AuthenticationSessionClusterTest extends AbstractClusterTest { driver.manage().deleteAllCookies(); } - Assert.assertThat(visitedRoutes, Matchers.containsInAnyOrder("node1", "node2")); + Assert.assertThat(visitedRoutes, Matchers.containsInAnyOrder(Matchers.startsWith("node1"), Matchers.startsWith("node2"))); } @@ -128,7 +128,7 @@ public class AuthenticationSessionClusterTest extends AbstractClusterTest { getTestingClientFor(backendNode(0)).server().run(session -> { Cache authSessionCache = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME); String keyOwner = InfinispanUtil.getTopologyInfo(session).getRouteName(authSessionCache, authSessionCookie); - Assert.assertEquals("node1", keyOwner); + Assert.assertTrue(keyOwner.startsWith("node1")); }); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionFailoverClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionFailoverClusterTest.java index a20e65b056..86675ce4e9 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionFailoverClusterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionFailoverClusterTest.java @@ -25,6 +25,7 @@ import org.jboss.arquillian.graphene.page.Page; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.keycloak.admin.client.resource.UserResource; import org.keycloak.models.UserModel; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.UserRepresentation; @@ -80,9 +81,10 @@ public class AuthenticationSessionFailoverClusterTest extends AbstractFailoverCl .enabled(true) .requiredAction(UserModel.RequiredAction.UPDATE_PASSWORD.toString()) .requiredAction(UserModel.RequiredAction.UPDATE_PROFILE.toString()) + .password("password") .build(); - userId = ApiUtil.createUserAndResetPasswordWithAdminClient(adminClient.realm("test"), user, "password"); + userId = ApiUtil.createUserWithAdminClient(adminClient.realm("test"), user); getCleanup().addUserId(userId); oauth.clientId("test-app"); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/ClientInvalidationClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/ClientInvalidationClusterTest.java index 1344d77e8f..e4903dc26a 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/ClientInvalidationClusterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/ClientInvalidationClusterTest.java @@ -4,6 +4,7 @@ import org.apache.commons.lang.RandomStringUtils; import org.junit.Before; import org.keycloak.admin.client.resource.ClientResource; import org.keycloak.admin.client.resource.ClientsResource; +import org.keycloak.common.util.Retry; import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.testsuite.admin.ApiUtil; import org.keycloak.testsuite.arquillian.ContainerInfo; @@ -58,24 +59,38 @@ public class ClientInvalidationClusterTest extends AbstractInvalidationClusterTe @Override protected ClientRepresentation readEntity(ClientRepresentation client, ContainerInfo node) { - ClientRepresentation u = null; - try { - u = entityResource(client, node).toRepresentation(); - } catch (NotFoundException nfe) { - // expected when client doesn't exist - } + ClientRepresentation u = Retry.call(new Retry.Supplier() { + @Override + public ClientRepresentation get(int iteration) { + try { + return entityResource(client, node).toRepresentation(); + } catch (NotFoundException nfe) { + return null; + } + } + }, 3, 5000); return u; } @Override protected ClientRepresentation updateEntity(ClientRepresentation client, ContainerInfo node) { - entityResource(client, node).update(client); + Retry.execute(new Runnable() { + @Override + public void run() { + entityResource(client, node).update(client); + } + }, 3, 5000); return readEntity(client, node); } @Override protected void deleteEntity(ClientRepresentation client, ContainerInfo node) { - entityResource(client, node).remove(); + Retry.execute(new Runnable() { + @Override + public void run() { + entityResource(client, node).remove(); + } + }, 3, 5000); assertNull(readEntity(client, node)); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/GroupInvalidationClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/GroupInvalidationClusterTest.java index b97d6e91e6..d45bc5599f 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/GroupInvalidationClusterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/GroupInvalidationClusterTest.java @@ -4,6 +4,7 @@ import org.apache.commons.lang.RandomStringUtils; import org.junit.Before; import org.keycloak.admin.client.resource.GroupResource; import org.keycloak.admin.client.resource.GroupsResource; +import org.keycloak.common.util.Retry; import org.keycloak.representations.idm.GroupRepresentation; import org.keycloak.testsuite.admin.ApiUtil; import org.keycloak.testsuite.arquillian.ContainerInfo; @@ -66,24 +67,38 @@ public class GroupInvalidationClusterTest extends AbstractInvalidationClusterTes @Override protected GroupRepresentation readEntity(GroupRepresentation group, ContainerInfo node) { - GroupRepresentation u = null; - try { - u = entityResource(group, node).toRepresentation(); - } catch (NotFoundException nfe) { - // expected when group doesn't exist - } + GroupRepresentation u = Retry.call(new Retry.Supplier() { + @Override + public GroupRepresentation get(int iteration) { + try { + return entityResource(group, node).toRepresentation(); + } catch (NotFoundException nfe) { + return null; + } + } + }, 3, 5000); return u; } @Override protected GroupRepresentation updateEntity(GroupRepresentation group, ContainerInfo node) { - entityResource(group, node).update(group); + Retry.execute(new Runnable() { + @Override + public void run() { + entityResource(group, node).update(group); + } + }, 3, 5000); return readEntity(group, node); } @Override protected void deleteEntity(GroupRepresentation group, ContainerInfo node) { - entityResource(group, node).remove(); + Retry.execute(new Runnable() { + @Override + public void run() { + entityResource(group, node).remove(); + } + }, 3, 5000); assertNull(readEntity(group, node)); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/RealmInvalidationClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/RealmInvalidationClusterTest.java index a054e7efbb..ed7562bae0 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/RealmInvalidationClusterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/RealmInvalidationClusterTest.java @@ -2,6 +2,7 @@ package org.keycloak.testsuite.cluster; import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.RealmsResource; +import org.keycloak.common.util.Retry; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.testsuite.arquillian.ContainerInfo; @@ -43,12 +44,16 @@ public class RealmInvalidationClusterTest extends AbstractInvalidationClusterTes @Override protected RealmRepresentation readEntity(RealmRepresentation realm, ContainerInfo node) { - RealmRepresentation realmOnNode = null; - try { - realmOnNode = entityResource(realm, node).toRepresentation(); - } catch (NotFoundException nfe) { - // expected if realm not found - } + RealmRepresentation realmOnNode = Retry.call(new Retry.Supplier() { + @Override + public RealmRepresentation get(int iteration) { + try { + return entityResource(realm, node).toRepresentation(); + } catch (NotFoundException nfe) { + return null; + } + } + }, 3, 5000); return realmOnNode; } @@ -58,7 +63,12 @@ public class RealmInvalidationClusterTest extends AbstractInvalidationClusterTes } private RealmRepresentation updateEntity(String realmName, RealmRepresentation realm, ContainerInfo node) { - entityResource(realmName, node).update(realm); + Retry.execute(new Runnable() { + @Override + public void run() { + entityResource(realmName, node).update(realm); + } + }, 3, 5000); return readEntity(realm, node); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/RoleInvalidationClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/RoleInvalidationClusterTest.java index c3ae0ea9dd..d776568843 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/RoleInvalidationClusterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/RoleInvalidationClusterTest.java @@ -3,6 +3,7 @@ package org.keycloak.testsuite.cluster; import org.apache.commons.lang.RandomStringUtils; import org.keycloak.admin.client.resource.RoleResource; import org.keycloak.admin.client.resource.RolesResource; +import org.keycloak.common.util.Retry; import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.testsuite.arquillian.ContainerInfo; @@ -48,11 +49,16 @@ public class RoleInvalidationClusterTest extends AbstractInvalidationClusterTest @Override protected RoleRepresentation readEntity(RoleRepresentation role, ContainerInfo node) { RoleRepresentation u = null; - try { - u = entityResource(role, node).toRepresentation(); - } catch (NotFoundException nfe) { - // expected when role doesn't exist - } + u = Retry.call(new Retry.Supplier() { + @Override + public RoleRepresentation get(int iteration) { + try { + return entityResource(role, node).toRepresentation(); + } catch (NotFoundException nfe) { + return null; + } + } + }, 3, 5000); return u; } @@ -62,13 +68,23 @@ public class RoleInvalidationClusterTest extends AbstractInvalidationClusterTest } private RoleRepresentation updateEntity(String roleName, RoleRepresentation role, ContainerInfo node) { - entityResource(roleName, node).update(role); + Retry.execute(new Runnable() { + @Override + public void run() { + entityResource(roleName, node).update(role); + } + }, 3, 5000); return readEntity(role, node); } @Override protected void deleteEntity(RoleRepresentation role, ContainerInfo node) { - entityResource(role, node).remove(); + Retry.execute(new Runnable() { + @Override + public void run() { + entityResource(role, node).remove(); + } + }, 3, 5000); assertNull(readEntity(role, node)); } 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 45e727a24c..33d42e824d 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml +++ b/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml @@ -619,9 +619,54 @@ ${auth.server.quarkus} org.keycloak.testsuite.arquillian.containers.KeycloakQuarkusServerDeployableContainer + ${auth.server.port.offset} + + + + + ${auth.server.quarkus.cluster} + org.keycloak.testsuite.arquillian.containers.KeycloakQuarkusServerDeployableContainer + localhost + ${auth.server.http.port} + ${auth.server.https.port} + 1 + 1 + node1 + ${quarkus.remote} + ha + { + "keycloak.connectionsInfinispan.jgroupsUdpMcastAddr": "234.56.78.8", + "keycloak.connectionsInfinispan.nodeName": "node1", + "keycloak.connectionsInfinispan.clustered": "${keycloak.connectionsInfinispan.clustered:true}" + } + + + + + + ${auth.server.quarkus.cluster} + org.keycloak.testsuite.arquillian.containers.KeycloakQuarkusServerDeployableContainer + localhost + ${auth.server.http.port} + ${auth.server.https.port} + 2 + 2 + node2 + ${quarkus.remote} + ha + { + "keycloak.connectionsInfinispan.jgroupsUdpMcastAddr": "234.56.78.8", + "keycloak.connectionsInfinispan.nodeName": "node2", + "keycloak.connectionsInfinispan.clustered": "${keycloak.connectionsInfinispan.clustered:true}" + } + + + + + diff --git a/testsuite/integration-arquillian/tests/pom.xml b/testsuite/integration-arquillian/tests/pom.xml index 5ba442a82c..3f0aa9878b 100755 --- a/testsuite/integration-arquillian/tests/pom.xml +++ b/testsuite/integration-arquillian/tests/pom.xml @@ -46,6 +46,7 @@ false false false + false false false @@ -77,6 +78,8 @@ integration-arquillian-servers-auth-server-${auth.server} ${auth.server.undertow} + true + false 300 @@ -215,6 +218,7 @@ false default + local @@ -260,6 +264,26 @@ *.jks,*.crt,*.truststore,*.crl,*.key,certs/clients/* + ${auth.server.undertow.skip.unpack} + + + + unpack-quarkus-server + generate-test-resources + + unpack + + + + + org.keycloak.testsuite + integration-arquillian-servers-auth-server-quarkus + ${project.version} + zip + ${containers.home} + + + ${auth.server.quarkus.skip.unpack} @@ -580,6 +604,8 @@ ${auth.server.undertow.cluster} ${auth.server.jboss.cluster} ${auth.server.jboss.legacy} + ${auth.server.quarkus.cluster} + ${auth.server.quarkus.config} ${auth.server.crossdc} @@ -701,9 +727,43 @@ false false ${auth.server.home}/conf + false + true + true + + auth-server-cluster-quarkus + + + - + true + true + ha + quarkus + true + false + false + ${auth.server.home}/conf + false + true + true + + + + + maven-surefire-plugin + + + 20000 + + + + + + + auth-server-wildfly