keycloak-uncached

KEYCLOAK-4187 SessionExpirationCrossDCTest - added tests

8/14/2017 3:27:01 AM

Details

diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/SessionUpdateTask.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/SessionUpdateTask.java
index 66f88ba..b79ea16 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/SessionUpdateTask.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/SessionUpdateTask.java
@@ -17,8 +17,6 @@
 
 package org.keycloak.models.sessions.infinispan.changes;
 
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.RealmModel;
 import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
 
 /**
diff --git a/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGSessionsCacheTest.java b/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGSessionsCacheTest.java
index dd34b19..825d05a 100644
--- a/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGSessionsCacheTest.java
+++ b/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/ConcurrencyJDGSessionsCacheTest.java
@@ -244,6 +244,10 @@ public class ConcurrencyJDGSessionsCacheTest {
             SessionEntity session = (SessionEntity) remoteCache.get(cacheKey);
             SessionEntityWrapper sessionWrapper = new SessionEntityWrapper(session);
 
+            if (listenerCount.get() % 100 == 0) {
+                logger.infof("Listener count: " + listenerCount.get());
+            }
+
             // TODO: for distributed caches, ensure that it is executed just on owner OR if event.isCommandRetried
             origCache
                     .getAdvancedCache().withFlags(Flag.SKIP_CACHE_LOAD, Flag.SKIP_CACHE_STORE)
diff --git a/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/TestCacheManagerFactory.java b/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/TestCacheManagerFactory.java
index 06dd95f..6b4eec1 100644
--- a/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/TestCacheManagerFactory.java
+++ b/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/TestCacheManagerFactory.java
@@ -60,8 +60,9 @@ class TestCacheManagerFactory {
     private <T extends RemoteStoreConfigurationBuilder> Configuration getCacheBackedByRemoteStore(int threadId, String cacheName, Class<T> builderClass) {
         ConfigurationBuilder cacheConfigBuilder = new ConfigurationBuilder();
 
+        String host = "localhost";
         int port = threadId==1 ? 12232 : 13232;
-        //int port = 12232;
+        //int port = 11222;
 
         return cacheConfigBuilder.persistence().addStore(builderClass)
                 .fetchPersistentState(false)
@@ -74,8 +75,8 @@ class TestCacheManagerFactory {
                 .forceReturnValues(false)
                 .marshaller(KeycloakHotRodMarshallerFactory.class.getName())
                 .addServer()
-                    .host("localhost")
-                .port(port)
+                    .host(host)
+                    .port(port)
                 .connectionPool()
                     .maxActive(20)
                     .exhaustedAction(ExhaustedAction.CREATE_NEW)
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/util/cli/AbstractSessionCacheCommand.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/util/cli/AbstractSessionCacheCommand.java
index 8ea51af..23760a1 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/util/cli/AbstractSessionCacheCommand.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/util/cli/AbstractSessionCacheCommand.java
@@ -17,16 +17,16 @@
 
 package org.keycloak.testsuite.util.cli;
 
-import java.util.function.Function;
-
 import org.infinispan.AdvancedCache;
 import org.infinispan.Cache;
 import org.infinispan.context.Flag;
 import org.keycloak.common.util.Time;
 import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
+import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
+import org.keycloak.models.UserSessionModel;
 import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
 import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
 import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
@@ -318,16 +318,20 @@ public abstract class AbstractSessionCacheCommand extends AbstractCommand {
         @Override
         protected void doRunCacheCommand(KeycloakSession session, Cache<String, SessionEntityWrapper> cache) {
             String realmName = getArg(1);
-            String username = getArg(2);
-            int count = getIntArg(3);
-            int batchCount = getIntArg(4);
+            String clientId = getArg(2);
+            String username = getArg(3);
+            int count = getIntArg(4);
+            int batchCount = getIntArg(5);
 
             BatchTaskRunner.runInBatches(0, count, batchCount, session.getKeycloakSessionFactory(), (KeycloakSession batchSession, int firstInIteration, int countInIteration) -> {
                 RealmModel realm = batchSession.realms().getRealmByName(realmName);
+                ClientModel client = realm.getClientByClientId(clientId);
                 UserModel user = batchSession.users().getUserByUsername(username, realm);
 
                 for (int i=0 ; i<countInIteration ; i++) {
-                    session.sessions().createUserSession(KeycloakModelUtils.generateId(), realm, user, username, "127.0.0.1", "form", false, null, null);
+                    UserSessionModel userSession = session.sessions().createUserSession(KeycloakModelUtils.generateId(), realm, user, username, "127.0.0.1", "form", false, null, null);
+
+                    session.sessions().createClientSession(userSession.getRealm(), client, userSession);
                 }
 
                 log.infof("Created '%d' sessions started from offset '%d'", countInIteration, firstInIteration);
@@ -338,7 +342,7 @@ public abstract class AbstractSessionCacheCommand extends AbstractCommand {
 
         @Override
         public String printUsage() {
-            return getName() + " <cache-name> <realm-name> <user-name> <count> <count-in-batch>";
+            return getName() + " <cache-name> <realm-name> <client-id> <user-name> <count> <count-in-batch>";
         }
 
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AuthServerTestEnricher.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AuthServerTestEnricher.java
index dc03248..f03a81d 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AuthServerTestEnricher.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AuthServerTestEnricher.java
@@ -173,7 +173,8 @@ public class AuthServerTestEnricher {
             if (suiteContext.getDcAuthServerBackendsInfo().stream().anyMatch(List::isEmpty)) {
                 throw new RuntimeException(String.format("Some data center has no auth server container matching '%s' defined in arquillian.xml.", AUTH_SERVER_BACKEND));
             }
-            if (suiteContext.getCacheServersInfo().isEmpty()) {
+            boolean cacheServerLifecycleSkip = Boolean.parseBoolean(System.getProperty("cache.server.lifecycle.skip"));
+            if (suiteContext.getCacheServersInfo().isEmpty() && !cacheServerLifecycleSkip) {
                 throw new IllegalStateException("Cache containers misconfiguration");
             }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/SessionExpirationCrossDCTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/SessionExpirationCrossDCTest.java
index 96a59d8..19e45d1 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/SessionExpirationCrossDCTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/crossdc/SessionExpirationCrossDCTest.java
@@ -24,11 +24,13 @@ import org.hamcrest.Matchers;
 import org.junit.Before;
 import org.junit.Test;
 import org.keycloak.OAuth2Constants;
+import org.keycloak.admin.client.resource.UserResource;
 import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
 import org.keycloak.models.Constants;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.representations.idm.UserSessionRepresentation;
 import org.keycloak.testsuite.Assert;
 import org.keycloak.testsuite.Retry;
 import org.keycloak.testsuite.admin.ApiUtil;
@@ -264,6 +266,80 @@ public class SessionExpirationCrossDCTest extends AbstractAdminCrossDCTest {
     }
 
 
+    // USER OPERATIONS
+
+    @Test
+    public void testUserRemoveSessions(
+            @JmxInfinispanCacheStatistics(dc=DC.FIRST, dcNodeIndex=0, cacheName=InfinispanConnectionProvider.SESSION_CACHE_NAME) InfinispanStatistics cacheDc1Statistics,
+            @JmxInfinispanCacheStatistics(dc=DC.SECOND, dcNodeIndex=0, cacheName=InfinispanConnectionProvider.SESSION_CACHE_NAME) InfinispanStatistics cacheDc2Statistics,
+            @JmxInfinispanChannelStatistics() InfinispanStatistics channelStatisticsCrossDc) throws Exception {
+        createInitialSessions(InfinispanConnectionProvider.SESSION_CACHE_NAME, false, cacheDc1Statistics, cacheDc2Statistics);
+
+//        log.infof("Sleeping!");
+//        Thread.sleep(10000000);
+
+        channelStatisticsCrossDc.reset();
+
+        // Remove test user
+        ApiUtil.findUserByUsernameId(getAdminClient().realm(REALM_NAME), "login-test").remove();
+
+
+        // Assert sessions removed on node1 and node2 and on remote caches. Assert that count of messages sent between DCs is not too big.
+        assertStatisticsExpected("After user remove", InfinispanConnectionProvider.SESSION_CACHE_NAME, cacheDc1Statistics, cacheDc2Statistics, channelStatisticsCrossDc,
+                sessions01, sessions02, remoteSessions01, remoteSessions02, 40l);
+    }
+
+
+    @Test
+    public void testUserRemoveOfflineSessions(
+            @JmxInfinispanCacheStatistics(dc=DC.FIRST, dcNodeIndex=0, cacheName=InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME) InfinispanStatistics cacheDc1Statistics,
+            @JmxInfinispanCacheStatistics(dc=DC.SECOND, dcNodeIndex=0, cacheName=InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME) InfinispanStatistics cacheDc2Statistics,
+            @JmxInfinispanChannelStatistics() InfinispanStatistics channelStatisticsCrossDc) throws Exception {
+        createInitialSessions(InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME, true, cacheDc1Statistics, cacheDc2Statistics);
+
+//        log.infof("Sleeping!");
+//        Thread.sleep(10000000);
+
+        channelStatisticsCrossDc.reset();
+
+        // Remove test user
+        ApiUtil.findUserByUsernameId(getAdminClient().realm(REALM_NAME), "login-test").remove();
+
+
+        // Assert sessions removed on node1 and node2 and on remote caches. Assert that count of messages sent between DCs is not too big.
+        assertStatisticsExpected("After user remove", InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME, cacheDc1Statistics, cacheDc2Statistics, channelStatisticsCrossDc,
+                sessions01, sessions02, remoteSessions01, remoteSessions02, 40l);
+    }
+
+
+    @Test
+    public void testLogoutUser(
+            @JmxInfinispanCacheStatistics(dc=DC.FIRST, dcNodeIndex=0, cacheName=InfinispanConnectionProvider.SESSION_CACHE_NAME) InfinispanStatistics cacheDc1Statistics,
+            @JmxInfinispanCacheStatistics(dc=DC.SECOND, dcNodeIndex=0, cacheName=InfinispanConnectionProvider.SESSION_CACHE_NAME) InfinispanStatistics cacheDc2Statistics,
+            @JmxInfinispanChannelStatistics() InfinispanStatistics channelStatisticsCrossDc) throws Exception {
+
+        createInitialSessions(InfinispanConnectionProvider.SESSION_CACHE_NAME, false, cacheDc1Statistics, cacheDc2Statistics);
+
+        channelStatisticsCrossDc.reset();
+
+        // Logout single session of user first
+        UserResource user = ApiUtil.findUserByUsernameId(getAdminClient().realm(REALM_NAME), "login-test");
+        UserSessionRepresentation userSession = user.getUserSessions().get(0);
+        getAdminClient().realm(REALM_NAME).deleteSession(userSession.getId());
+
+        // Just one session expired. Limit 5 for sent_messages is just if "lastSessionRefresh" periodic thread happened
+        assertStatisticsExpected("After logout single session", InfinispanConnectionProvider.SESSION_CACHE_NAME, cacheDc1Statistics, cacheDc2Statistics, channelStatisticsCrossDc,
+                sessions01 + SESSIONS_COUNT - 1, sessions02 + SESSIONS_COUNT - 1, remoteSessions01 + SESSIONS_COUNT - 1, remoteSessions02 + SESSIONS_COUNT - 1, 5l);
+
+        // Logout all sessions for user now
+        user.logout();
+
+        // Assert sessions removed on node1 and node2 and on remote caches. Assert that count of messages sent between DCs is not too big.
+        assertStatisticsExpected("After user logout", InfinispanConnectionProvider.SESSION_CACHE_NAME, cacheDc1Statistics, cacheDc2Statistics, channelStatisticsCrossDc,
+                sessions01, sessions02, remoteSessions01, remoteSessions02, 40l);
+    }
+
+
 
 
     // AUTH SESSIONS