Test AuthenticationSession optimization

Closes #35513

Signed-off-by: Pedro Ruivo <pruivo@redhat.com>
This commit is contained in:
Pedro Ruivo
2024-12-02 11:07:31 +00:00
committed by Alexander Schwartz
parent a4d70ad6d2
commit ff939d6b28
2 changed files with 54 additions and 0 deletions
@@ -184,4 +184,8 @@ public class HotRodServerRule extends ExternalResource {
public DefaultCacheManager getHotRodCacheManager2() {
return hotRodCacheManager2;
}
public Stream<DefaultCacheManager> streamCacheManagers() {
return Stream.of(hotRodCacheManager, hotRodCacheManager2);
}
}
@@ -18,8 +18,13 @@
package org.keycloak.testsuite.model.session;
import org.hamcrest.Matchers;
import org.infinispan.Cache;
import org.infinispan.factories.ComponentRegistry;
import org.infinispan.interceptors.AsyncInterceptorChain;
import org.infinispan.interceptors.impl.CacheMgmtInterceptor;
import org.junit.Assert;
import org.junit.Test;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
@@ -27,6 +32,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.sessions.AuthenticationSessionModel;
import org.keycloak.sessions.AuthenticationSessionProvider;
import org.keycloak.sessions.RootAuthenticationSessionModel;
import org.keycloak.testsuite.model.HotRodServerRule;
import org.keycloak.testsuite.model.KeycloakModelTest;
import org.keycloak.testsuite.model.RequireProvider;
@@ -34,6 +40,7 @@ import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.LongSupplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@@ -253,4 +260,47 @@ public class AuthenticationSessionTest extends KeycloakModelTest {
return null;
});
}
@Test
public void testRemoveAfterCreation() {
var computeOperationCount = operationCounterSupplier();
var operationsBefore = computeOperationCount.getAsLong();
withRealmConsumer(realmId, (session, realm) -> {
// optimization in place:
// create and remove in the same transaction should not trigger any operation in the Infinispan cache.
var rootAuthSession = session.authenticationSessions().createRootAuthenticationSession(realm);
rootAuthSession.setTimestamp(1000);
session.authenticationSessions().removeRootAuthenticationSession(realm, rootAuthSession);
});
var operationsAfter = computeOperationCount.getAsLong();
Assert.assertEquals("No operations expected in the cache", operationsBefore, operationsAfter);
}
private static long getNumberOfOperations(Cache<?, ?> cache) {
var statsInterceptor = ComponentRegistry.componentOf(cache, AsyncInterceptorChain.class).findInterceptorWithClass(CacheMgmtInterceptor.class);
statsInterceptor.setStatisticsEnabled(true);
return statsInterceptor.getHits() + statsInterceptor.getMisses() + // reads
statsInterceptor.getStores() + // writes
statsInterceptor.getRemoveHits() + statsInterceptor.getRemoveMisses(); // removes
}
private LongSupplier operationCounterSupplier() {
var hotRodServers = getParameters(HotRodServerRule.class).findFirst();
if (hotRodServers.isEmpty()) {
// fetch stats from embedded cache
return () -> withRealm(realmId, (session, realm) -> {
var cache = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME);
return getNumberOfOperations(cache);
});
}
// fetch stats from external cache
return () -> hotRodServers.stream()
.flatMap(HotRodServerRule::streamCacheManagers)
.map(manager -> manager.getCache(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME))
.mapToLong(AuthenticationSessionTest::getNumberOfOperations)
.sum();
}
}