From 4946484cb6b5b99440e8087851a9cde1e40feaf5 Mon Sep 17 00:00:00 2001 From: Hynek Mlnarik Date: Thu, 11 Mar 2021 09:35:37 +0100 Subject: [PATCH] KEYCLOAK-17377 Fix invalidation cluster tests (do not hide failures) --- ...ltInfinispanConnectionProviderFactory.java | 8 +-- .../default-keycloak-jgroups-udp.xml | 61 +++++++++++++++++++ .../filters/AbstractRequestFilter.java | 6 +- .../undertow/KeycloakOnUndertow.java | 18 +++++- .../AbstractInvalidationClusterTest.java | 12 +++- .../ClientInvalidationClusterTest.java | 31 +++------- .../cluster/GroupInvalidationClusterTest.java | 31 +++------- .../cluster/RealmInvalidationClusterTest.java | 24 +++----- .../cluster/RoleInvalidationClusterTest.java | 30 +++------ .../integration-arquillian/tests/pom.xml | 3 + .../keycloak/testsuite/KeycloakServer.java | 14 ++++- .../testsuite/UndertowRequestFilter.java | 12 ++++ 12 files changed, 153 insertions(+), 97 deletions(-) create mode 100644 model/infinispan/src/main/resources/default-configs/default-keycloak-jgroups-udp.xml diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java index 871c7417b7..3eb35ada80 100755 --- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java +++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java @@ -21,10 +21,7 @@ import java.util.Iterator; import java.util.ServiceLoader; import java.util.concurrent.TimeUnit; -import org.infinispan.Cache; import org.infinispan.client.hotrod.ProtocolVersion; -import org.infinispan.client.hotrod.RemoteCache; -import org.infinispan.commons.configuration.Builder; import org.infinispan.commons.util.FileLookup; import org.infinispan.commons.util.FileLookupFactory; import org.infinispan.configuration.cache.CacheMode; @@ -465,8 +462,7 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon System.setProperty(InfinispanConnectionProvider.JGROUPS_UDP_MCAST_ADDR, jgroupsUdpMcastAddr); } try { - // Compatibility with Wildfly - JChannel channel = new JChannel(fileLookup.lookupFileLocation("default-configs/default-jgroups-udp.xml", this.getClass().getClassLoader()).openStream()); + JChannel channel = new JChannel(fileLookup.lookupFileLocation("default-configs/default-keycloak-jgroups-udp.xml", this.getClass().getClassLoader()).openStream()); channel.setName(nodeName); JGroupsTransport transport = new JGroupsTransport(channel); @@ -482,7 +478,7 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon transportBuilder.jmx() - .jmxDomain(InfinispanConnectionProvider.JMX_DOMAIN + "-" + nodeName) + .domain(InfinispanConnectionProvider.JMX_DOMAIN + "-" + nodeName) .enable(); logger.infof("Configured jgroups transport with the channel name: %s", nodeName); diff --git a/model/infinispan/src/main/resources/default-configs/default-keycloak-jgroups-udp.xml b/model/infinispan/src/main/resources/default-configs/default-keycloak-jgroups-udp.xml new file mode 100644 index 0000000000..0971e53c17 --- /dev/null +++ b/model/infinispan/src/main/resources/default-configs/default-keycloak-jgroups-udp.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + diff --git a/services/src/main/java/org/keycloak/services/filters/AbstractRequestFilter.java b/services/src/main/java/org/keycloak/services/filters/AbstractRequestFilter.java index edf00ed353..2672acd891 100644 --- a/services/src/main/java/org/keycloak/services/filters/AbstractRequestFilter.java +++ b/services/src/main/java/org/keycloak/services/filters/AbstractRequestFilter.java @@ -30,7 +30,7 @@ import org.keycloak.services.resources.KeycloakApplication; public abstract class AbstractRequestFilter { protected void filter(ClientConnection clientConnection, Consumer next) { - KeycloakSessionFactory sessionFactory = KeycloakApplication.getSessionFactory(); + KeycloakSessionFactory sessionFactory = getSessionFactory(); KeycloakSession session = sessionFactory.create(); KeycloakTransactionManager tx = session.getTransactionManager(); @@ -51,6 +51,10 @@ public abstract class AbstractRequestFilter { } } + protected KeycloakSessionFactory getSessionFactory() { + return KeycloakApplication.getSessionFactory(); + } + protected void close(KeycloakSession session) { KeycloakTransactionManager tx = session.getTransactionManager(); if (tx.isActive()) { diff --git a/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java b/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java index 1432509ce2..92b3bb7b6a 100644 --- a/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java +++ b/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java @@ -39,7 +39,6 @@ import org.jboss.logging.Logger; import org.jboss.resteasy.plugins.server.servlet.ResteasyContextParameters; import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer; import org.jboss.resteasy.spi.ResteasyDeployment; -import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.jboss.shrinkwrap.api.Archive; import org.jboss.shrinkwrap.api.spec.WebArchive; import org.jboss.shrinkwrap.descriptor.api.Descriptor; @@ -57,6 +56,7 @@ import org.keycloak.testsuite.utils.undertow.UndertowDeployerHelper; import org.keycloak.testsuite.utils.undertow.UndertowWarClassLoader; import org.keycloak.util.JsonSerialization; +import io.undertow.servlet.api.InstanceHandle; import javax.servlet.DispatcherType; import javax.servlet.ServletException; import java.io.IOException; @@ -64,6 +64,7 @@ import java.lang.reflect.Field; import java.util.Collection; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import javax.servlet.Filter; import org.xnio.Options; import org.xnio.SslClientAuthMode; @@ -103,7 +104,20 @@ public class KeycloakOnUndertow implements DeployableContainer filterInstance = new InstanceHandle() { + @Override + public Filter getInstance() { + return new UndertowRequestFilter(sessionFactory); + } + + @Override + public void release() { + } + }; + FilterInfo filter = Servlets.filter("SessionFilter", UndertowRequestFilter.class, () -> filterInstance); di.addFilter(filter); di.addFilterUrlMapping("SessionFilter", "/*", DispatcherType.REQUEST); filter.setAsyncSupported(true); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractInvalidationClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractInvalidationClusterTest.java index 33d82970d3..960e6be485 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractInvalidationClusterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AbstractInvalidationClusterTest.java @@ -49,28 +49,37 @@ public abstract class AbstractInvalidationClusterTest extends AbstractClu public void crud(boolean backendFailover) { T testEntity = createTestEntityRepresentation(); - // CREATE + // CREATE + log.info("(1) createEntityOnCurrentFailNode"); testEntity = createEntityOnCurrentFailNode(testEntity); if (backendFailover) { + log.info("(2) failure"); failure(); } + log.info("(3) assertEntityOnSurvivorNodesEqualsTo"); assertEntityOnSurvivorNodesEqualsTo(testEntity); + log.info("(4) failback"); failback(); + log.info("(5) iterateCurrentFailNode"); iterateCurrentFailNode(); // UPDATE(s) + log.info("(6) testEntityUpdates"); testEntity = testEntityUpdates(testEntity, backendFailover); // DELETE + log.info("(7) deleteEntityOnCurrentFailNode"); deleteEntityOnCurrentFailNode(testEntity); if (backendFailover) { + log.info("(8) failure"); failure(); } + log.info("(9) assertEntityOnSurvivorNodesIsDeleted"); assertEntityOnSurvivorNodesIsDeleted(testEntity); } @@ -136,6 +145,7 @@ public abstract class AbstractInvalidationClusterTest extends AbstractClu protected void assertEntityOnSurvivorNodesEqualsTo(T testEntityOnFailNode) { boolean entityDiffers = false; for (ContainerInfo survivorNode : getCurrentSurvivorNodes()) { + log.debug(String.format("Attempt to verify %s on survivor %s (%s)", getEntityType(testEntityOnFailNode), survivorNode, survivorNode.getContextRoot())); T testEntityOnSurvivorNode = readEntity(testEntityOnFailNode, survivorNode); if (EqualsBuilder.reflectionEquals(sortFields(testEntityOnSurvivorNode), sortFields(testEntityOnFailNode), excludedComparisonFields)) { 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 e4903dc26a..1344d77e8f 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,7 +4,6 @@ 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; @@ -59,38 +58,24 @@ public class ClientInvalidationClusterTest extends AbstractInvalidationClusterTe @Override protected ClientRepresentation readEntity(ClientRepresentation client, ContainerInfo node) { - 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); + ClientRepresentation u = null; + try { + u = entityResource(client, node).toRepresentation(); + } catch (NotFoundException nfe) { + // expected when client doesn't exist + } return u; } @Override protected ClientRepresentation updateEntity(ClientRepresentation client, ContainerInfo node) { - Retry.execute(new Runnable() { - @Override - public void run() { - entityResource(client, node).update(client); - } - }, 3, 5000); + entityResource(client, node).update(client); return readEntity(client, node); } @Override protected void deleteEntity(ClientRepresentation client, ContainerInfo node) { - Retry.execute(new Runnable() { - @Override - public void run() { - entityResource(client, node).remove(); - } - }, 3, 5000); + entityResource(client, node).remove(); 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 d45bc5599f..b97d6e91e6 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,7 +4,6 @@ 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; @@ -67,38 +66,24 @@ public class GroupInvalidationClusterTest extends AbstractInvalidationClusterTes @Override protected GroupRepresentation readEntity(GroupRepresentation group, ContainerInfo node) { - 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); + GroupRepresentation u = null; + try { + u = entityResource(group, node).toRepresentation(); + } catch (NotFoundException nfe) { + // expected when group doesn't exist + } return u; } @Override protected GroupRepresentation updateEntity(GroupRepresentation group, ContainerInfo node) { - Retry.execute(new Runnable() { - @Override - public void run() { - entityResource(group, node).update(group); - } - }, 3, 5000); + entityResource(group, node).update(group); return readEntity(group, node); } @Override protected void deleteEntity(GroupRepresentation group, ContainerInfo node) { - Retry.execute(new Runnable() { - @Override - public void run() { - entityResource(group, node).remove(); - } - }, 3, 5000); + entityResource(group, node).remove(); 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 ed7562bae0..a054e7efbb 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,7 +2,6 @@ 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; @@ -44,16 +43,12 @@ public class RealmInvalidationClusterTest extends AbstractInvalidationClusterTes @Override protected RealmRepresentation readEntity(RealmRepresentation realm, ContainerInfo node) { - 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); + RealmRepresentation realmOnNode = null; + try { + realmOnNode = entityResource(realm, node).toRepresentation(); + } catch (NotFoundException nfe) { + // expected if realm not found + } return realmOnNode; } @@ -63,12 +58,7 @@ public class RealmInvalidationClusterTest extends AbstractInvalidationClusterTes } private RealmRepresentation updateEntity(String realmName, RealmRepresentation realm, ContainerInfo node) { - Retry.execute(new Runnable() { - @Override - public void run() { - entityResource(realmName, node).update(realm); - } - }, 3, 5000); + entityResource(realmName, node).update(realm); 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 d776568843..c3ae0ea9dd 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,7 +3,6 @@ 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; @@ -49,16 +48,11 @@ public class RoleInvalidationClusterTest extends AbstractInvalidationClusterTest @Override protected RoleRepresentation readEntity(RoleRepresentation role, ContainerInfo node) { RoleRepresentation u = null; - 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); + try { + u = entityResource(role, node).toRepresentation(); + } catch (NotFoundException nfe) { + // expected when role doesn't exist + } return u; } @@ -68,23 +62,13 @@ public class RoleInvalidationClusterTest extends AbstractInvalidationClusterTest } private RoleRepresentation updateEntity(String roleName, RoleRepresentation role, ContainerInfo node) { - Retry.execute(new Runnable() { - @Override - public void run() { - entityResource(roleName, node).update(role); - } - }, 3, 5000); + entityResource(roleName, node).update(role); return readEntity(role, node); } @Override protected void deleteEntity(RoleRepresentation role, ContainerInfo node) { - Retry.execute(new Runnable() { - @Override - public void run() { - entityResource(role, node).remove(); - } - }, 3, 5000); + entityResource(role, node).remove(); assertNull(readEntity(role, node)); } diff --git a/testsuite/integration-arquillian/tests/pom.xml b/testsuite/integration-arquillian/tests/pom.xml index d20a8dc107..a506ee104e 100755 --- a/testsuite/integration-arquillian/tests/pom.xml +++ b/testsuite/integration-arquillian/tests/pom.xml @@ -641,6 +641,7 @@ ${keycloak.connectionsInfinispan.remoteStorePort} ${keycloak.connectionsInfinispan.remoteStorePort.2} ${keycloak.connectionsInfinispan.remoteStoreServer} + ${keycloak.connectionsInfinispan.sessionsOwners} ${keycloak.testsuite.logging.pattern} ${keycloak.connectionsJpa.url.crossdc} @@ -771,6 +772,7 @@ false true true + 2 @@ -1246,6 +1248,7 @@ true + 2 diff --git a/testsuite/utils/src/main/java/org/keycloak/testsuite/KeycloakServer.java b/testsuite/utils/src/main/java/org/keycloak/testsuite/KeycloakServer.java index e4bf8c9412..10509d8210 100755 --- a/testsuite/utils/src/main/java/org/keycloak/testsuite/KeycloakServer.java +++ b/testsuite/utils/src/main/java/org/keycloak/testsuite/KeycloakServer.java @@ -37,6 +37,7 @@ import org.keycloak.services.managers.RealmManager; import org.keycloak.services.resources.KeycloakApplication; import org.keycloak.testsuite.util.cli.TestsuiteCLI; import org.keycloak.util.JsonSerialization; +import io.undertow.servlet.api.InstanceHandle; import org.xnio.Options; import org.xnio.SslClientAuthMode; @@ -58,6 +59,7 @@ import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.Properties; +import javax.servlet.Filter; /** * @author Stian Thorgersen @@ -406,7 +408,17 @@ public class KeycloakServer { // KEYCLOAK-14178 deployment.setProperty(ResteasyContextParameters.RESTEASY_DISABLE_HTML_SANITIZER, true); - FilterInfo filter = Servlets.filter("SessionFilter", UndertowRequestFilter.class); + InstanceHandle filterInstance = new InstanceHandle() { + @Override + public Filter getInstance() { + return new UndertowRequestFilter(sessionFactory); + } + + @Override + public void release() { + } + }; + FilterInfo filter = Servlets.filter("SessionFilter", UndertowRequestFilter.class, () -> filterInstance); filter.setAsyncSupported(true); di.addFilter(filter); diff --git a/testsuite/utils/src/main/java/org/keycloak/testsuite/UndertowRequestFilter.java b/testsuite/utils/src/main/java/org/keycloak/testsuite/UndertowRequestFilter.java index 320762c617..979241d0a5 100755 --- a/testsuite/utils/src/main/java/org/keycloak/testsuite/UndertowRequestFilter.java +++ b/testsuite/utils/src/main/java/org/keycloak/testsuite/UndertowRequestFilter.java @@ -27,10 +27,17 @@ import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import org.keycloak.common.ClientConnection; +import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.services.filters.AbstractRequestFilter; public class UndertowRequestFilter extends AbstractRequestFilter implements Filter { + private final KeycloakSessionFactory factory; + + public UndertowRequestFilter(KeycloakSessionFactory factory) { + this.factory = factory; + } + @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws UnsupportedEncodingException { @@ -81,6 +88,11 @@ public class UndertowRequestFilter extends AbstractRequestFilter implements Filt }; } + @Override + protected KeycloakSessionFactory getSessionFactory() { + return this.factory; + } + @Override public void init(FilterConfig filterConfig) { }