Leverage Infinispan lifespan for ExpirableEntities in HotRod storage
This commit is contained in:
parent
fc075a3d35
commit
5ba004b447
27 changed files with 435 additions and 62 deletions
|
@ -45,12 +45,12 @@ import org.keycloak.storage.SearchableModelField;
|
|||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Spliterators;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import static org.keycloak.models.map.common.ExpirationUtils.isExpired;
|
||||
import static org.keycloak.models.map.storage.hotRod.common.HotRodUtils.paginateQuery;
|
||||
import static org.keycloak.utils.StreamsUtil.closing;
|
||||
|
||||
|
@ -82,6 +82,17 @@ public class HotRodMapStorage<K, E extends AbstractHotRodEntity, V extends Abstr
|
|||
value = cloner.from(keyConverter.keyToString(key), value);
|
||||
}
|
||||
|
||||
if (isExpirableEntity) {
|
||||
Long lifespan = getLifespan(value);
|
||||
if (lifespan != null) {
|
||||
if (lifespan > 0) {
|
||||
remoteCache.putIfAbsent(key, value.getHotRodEntity(), lifespan, TimeUnit.MILLISECONDS);
|
||||
} else {
|
||||
LOG.warnf("Skipped creation of entity %s in storage due to negative/zero lifespan.", key);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
remoteCache.putIfAbsent(key, value.getHotRodEntity());
|
||||
|
||||
return value;
|
||||
|
@ -97,20 +108,28 @@ public class HotRodMapStorage<K, E extends AbstractHotRodEntity, V extends Abstr
|
|||
if (hotRodEntity == null) return null;
|
||||
|
||||
// Create delegate that implements Map*Entity
|
||||
V delegateEntity = delegateProducer.apply(hotRodEntity);
|
||||
|
||||
// Check expiration if necessary and return value
|
||||
return isExpirableEntity && isExpired((ExpirableEntity) delegateEntity, true) ? null : delegateEntity;
|
||||
return delegateProducer.apply(hotRodEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V update(V value) {
|
||||
K key = keyConverter.fromStringSafe(value.getId());
|
||||
|
||||
if (isExpirableEntity) {
|
||||
Long lifespan = getLifespan(value);
|
||||
if (lifespan != null) {
|
||||
E previousValue;
|
||||
if (lifespan > 0) {
|
||||
previousValue = remoteCache.replace(key, value.getHotRodEntity(), lifespan, TimeUnit.MILLISECONDS);
|
||||
} else {
|
||||
LOG.warnf("Removing entity %s from storage due to negative/zero lifespan.", key);
|
||||
previousValue = remoteCache.remove(key);
|
||||
}
|
||||
return previousValue == null ? null : delegateProducer.apply(previousValue);
|
||||
}
|
||||
}
|
||||
E previousValue = remoteCache.replace(key, value.getHotRodEntity());
|
||||
if (previousValue == null) return null;
|
||||
|
||||
return delegateProducer.apply(previousValue);
|
||||
return previousValue == null ? null : delegateProducer.apply(previousValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -127,22 +146,12 @@ public class HotRodMapStorage<K, E extends AbstractHotRodEntity, V extends Abstr
|
|||
return modelFieldName + " " + orderString;
|
||||
}
|
||||
|
||||
private static String isNotExpiredIckleWhereClause() {
|
||||
return "(" + IckleQueryOperators.C + ".expiration > " + Time.currentTimeMillis() + " OR "
|
||||
+ IckleQueryOperators.C + ".expiration is null)";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<V> read(QueryParameters<M> queryParameters) {
|
||||
IckleQueryMapModelCriteriaBuilder<E, M> iqmcb = queryParameters.getModelCriteriaBuilder()
|
||||
.flashToModelCriteriaBuilder(createCriteriaBuilder());
|
||||
String queryString = iqmcb.getIckleQuery();
|
||||
|
||||
// Temporary solution until https://github.com/keycloak/keycloak/issues/12068 is fixed
|
||||
if (isExpirableEntity) {
|
||||
queryString += (queryString.contains("WHERE") ? " AND " : " WHERE ") + isNotExpiredIckleWhereClause();
|
||||
}
|
||||
|
||||
if (!queryParameters.getOrderBy().isEmpty()) {
|
||||
queryString += " ORDER BY " + queryParameters.getOrderBy().stream().map(HotRodMapStorage::toOrderString)
|
||||
.collect(Collectors.joining(", "));
|
||||
|
@ -232,4 +241,12 @@ public class HotRodMapStorage<K, E extends AbstractHotRodEntity, V extends Abstr
|
|||
Map<SearchableModelField<? super M>, MapModelCriteriaBuilder.UpdatePredicatesFunc<K, V, M>> fieldPredicates = MapFieldPredicates.getPredicates((Class<M>) storedEntityDescriptor.getModelTypeClass());
|
||||
return new ConcurrentHashMapKeycloakTransaction<>(this, keyConverter, cloner, fieldPredicates);
|
||||
}
|
||||
|
||||
// V must be an instance of ExpirableEntity
|
||||
// returns null if expiration field is not set
|
||||
// in certain cases can return 0 or negative number, which needs to be handled carefully when using as ISPN lifespan
|
||||
private Long getLifespan(V value) {
|
||||
Long expiration = ((ExpirableEntity) value).getExpiration();
|
||||
return expiration != null ? expiration - Time.currentTimeMillis() : null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,7 +78,6 @@ public class HotRodRootAuthenticationSessionEntity extends AbstractHotRodEntity
|
|||
@ProtoField(number = 4)
|
||||
public Long timestamp;
|
||||
|
||||
@Basic(sortable = true)
|
||||
@ProtoField(number = 5)
|
||||
public Long expiration;
|
||||
|
||||
|
|
|
@ -26,12 +26,14 @@ import org.infinispan.commons.marshall.ProtoStreamMarshaller;
|
|||
import org.infinispan.protostream.GeneratedSchema;
|
||||
import org.infinispan.query.remote.client.ProtobufMetadataManagerConstants;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.map.storage.hotRod.locking.HotRodLocksUtils;
|
||||
import org.keycloak.models.map.storage.hotRod.common.HotRodEntityDescriptor;
|
||||
import org.keycloak.models.map.storage.hotRod.common.CommonPrimitivesProtoSchemaInitializer;
|
||||
import org.keycloak.models.map.storage.hotRod.common.HotRodVersionUtils;
|
||||
import org.keycloak.provider.EnvironmentDependentProviderFactory;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
@ -49,9 +51,10 @@ import static org.keycloak.models.map.storage.hotRod.common.HotRodVersionUtils.i
|
|||
/**
|
||||
* @author <a href="mailto:mkanis@redhat.com">Martin Kanis</a>
|
||||
*/
|
||||
public class DefaultHotRodConnectionProviderFactory implements HotRodConnectionProviderFactory {
|
||||
public class DefaultHotRodConnectionProviderFactory implements HotRodConnectionProviderFactory, EnvironmentDependentProviderFactory {
|
||||
|
||||
public static final String PROVIDER_ID = "default";
|
||||
public static final String SCRIPT_CACHE = "___script_cache";
|
||||
public static final String HOT_ROD_LOCKS_CACHE_NAME = "locks";
|
||||
private static final String HOT_ROD_INIT_LOCK_NAME = "HOT_ROD_INIT_LOCK";
|
||||
private static final Logger LOG = Logger.getLogger(DefaultHotRodConnectionProviderFactory.class);
|
||||
|
@ -267,4 +270,9 @@ public class DefaultHotRodConnectionProviderFactory implements HotRodConnectionP
|
|||
.nearCacheUseBloomFilter(config.scope(cacheName).getBoolean("nearCacheBloomFilter", config.getBoolean("nearCacheBloomFilter", false)));
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
return Profile.isFeatureEnabled(Profile.Feature.MAP_STORAGE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,6 @@ public class HotRodAdminEventEntity extends AbstractHotRodEntity {
|
|||
@ProtoField(number = 2)
|
||||
public String id;
|
||||
|
||||
@Basic(sortable = true)
|
||||
@ProtoField(number = 3)
|
||||
public Long expiration;
|
||||
|
||||
|
|
|
@ -68,7 +68,6 @@ public class HotRodAuthEventEntity extends AbstractHotRodEntity {
|
|||
@ProtoField(number = 3)
|
||||
public Integer type;
|
||||
|
||||
@Basic(sortable = true)
|
||||
@ProtoField(number = 4)
|
||||
public Long expiration;
|
||||
|
||||
|
|
|
@ -109,7 +109,6 @@ public class HotRodUserSessionEntity extends AbstractHotRodEntity {
|
|||
@ProtoField(number = 12)
|
||||
public Long lastSessionRefresh;
|
||||
|
||||
@Basic(sortable = true)
|
||||
@ProtoField(number = 13)
|
||||
public Long expiration;
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.keycloak.storage.SearchableModelField;
|
|||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -65,6 +66,7 @@ public class HotRodUserSessionTransaction<K> extends ConcurrentHashMapKeycloakTr
|
|||
}
|
||||
|
||||
private MapAuthenticatedClientSessionEntity wrapClientSessionEntityToClientSessionAwareDelegate(MapAuthenticatedClientSessionEntity d) {
|
||||
if (!clientSessionTransaction.exists(d.getId())) return null;
|
||||
return new MapAuthenticatedClientSessionEntityDelegate(new HotRodAuthenticatedClientSessionEntityDelegateProvider(d) {
|
||||
@Override
|
||||
public MapAuthenticatedClientSessionEntity loadClientSessionFromDatabase() {
|
||||
|
@ -82,13 +84,15 @@ public class HotRodUserSessionTransaction<K> extends ConcurrentHashMapKeycloakTr
|
|||
Set<MapAuthenticatedClientSessionEntity> clientSessions = super.getAuthenticatedClientSessions();
|
||||
return clientSessions == null ? null : clientSessions.stream()
|
||||
.map(HotRodUserSessionTransaction.this::wrapClientSessionEntityToClientSessionAwareDelegate)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<MapAuthenticatedClientSessionEntity> getAuthenticatedClientSession(String clientUUID) {
|
||||
return super.getAuthenticatedClientSession(clientUUID)
|
||||
.map(HotRodUserSessionTransaction.this::wrapClientSessionEntityToClientSessionAwareDelegate);
|
||||
.map(HotRodUserSessionTransaction.this::wrapClientSessionEntityToClientSessionAwareDelegate)
|
||||
.filter(Objects::nonNull);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -67,6 +67,11 @@
|
|||
<version>${project.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.infinispan</groupId>
|
||||
<artifactId>infinispan-tasks-api</artifactId>
|
||||
<version>${infinispan.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright 2023 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.model.infinispan;
|
||||
|
||||
import org.infinispan.commons.logging.Log;
|
||||
import org.infinispan.commons.logging.LogFactory;
|
||||
import org.infinispan.commons.time.TimeService;
|
||||
import org.infinispan.expiration.ExpirationManager;
|
||||
import org.infinispan.factories.GlobalComponentRegistry;
|
||||
import org.infinispan.factories.impl.BasicComponentRegistry;
|
||||
import org.infinispan.manager.EmbeddedCacheManager;
|
||||
import org.infinispan.tasks.ServerTask;
|
||||
import org.infinispan.tasks.TaskContext;
|
||||
import org.infinispan.tasks.TaskExecutionMode;
|
||||
import org.infinispan.util.EmbeddedTimeService;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class InfinispanTimeServiceTask implements ServerTask<String> {
|
||||
|
||||
private static final Log log = LogFactory.getLog(InfinispanTimeServiceTask.class);
|
||||
private TaskContext context = null;
|
||||
private static int offset;
|
||||
|
||||
public InfinispanTimeServiceTask() {
|
||||
log.info("InfinispanTimeServiceTask construction");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String call() {
|
||||
EmbeddedCacheManager cacheManager = context.getCacheManager();
|
||||
Map<String, Object> params = new HashMap();
|
||||
if (this.context.getParameters().isPresent())
|
||||
params = this.context.getParameters().get();
|
||||
if (params.containsKey("timeService")) {
|
||||
offset = (int) params.get("timeService");
|
||||
|
||||
// rewire the Time service
|
||||
GlobalComponentRegistry cr = cacheManager.getGlobalComponentRegistry();
|
||||
BasicComponentRegistry bcr = cr.getComponent(BasicComponentRegistry.class);
|
||||
bcr.replaceComponent(TimeService.class.getName(), KEYCLOAK_TIME_SERVICE, true);
|
||||
cr.rewire();
|
||||
cr.rewireNamedRegistries();
|
||||
|
||||
// process expiration in all caches
|
||||
cacheManager.getCacheNames().stream()
|
||||
.map(cacheManager::getCache)
|
||||
.filter(Objects::nonNull)
|
||||
.map(cache -> cache.getAdvancedCache().getExpirationManager())
|
||||
.forEach(ExpirationManager::processExpiration);
|
||||
}
|
||||
|
||||
return "InfinispanTimeServiceTask: Infinispan server time moved by " + offset + " seconds.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
log.info("getName() called");
|
||||
return "InfinispanTimeServiceTask";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTaskContext(TaskContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskExecutionMode getExecutionMode() {
|
||||
return TaskExecutionMode.ALL_NODES;
|
||||
}
|
||||
|
||||
public static final TimeService KEYCLOAK_TIME_SERVICE = new EmbeddedTimeService() {
|
||||
|
||||
private long getCurrentTimeMillis() {
|
||||
return System.currentTimeMillis() + (TimeUnit.SECONDS.toMillis(offset));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long wallClockTime() {
|
||||
return getCurrentTimeMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long time() {
|
||||
return TimeUnit.MILLISECONDS.toNanos(getCurrentTimeMillis());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant instant() {
|
||||
return Instant.ofEpochMilli(getCurrentTimeMillis());
|
||||
}
|
||||
};
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package org.keycloak.testsuite.rest;
|
||||
|
||||
import org.infinispan.client.hotrod.RemoteCache;
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.keycloak.http.HttpRequest;
|
||||
import org.keycloak.Config;
|
||||
|
@ -45,6 +46,13 @@ import org.keycloak.models.UserCredentialModel;
|
|||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserProvider;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.UserSessionProvider;
|
||||
import org.keycloak.models.UserSessionSpi;
|
||||
import org.keycloak.models.map.common.AbstractMapProviderFactory;
|
||||
import org.keycloak.models.map.storage.MapStorageProvider;
|
||||
import org.keycloak.models.map.storage.hotRod.connections.DefaultHotRodConnectionProviderFactory;
|
||||
import org.keycloak.models.map.storage.hotRod.connections.HotRodConnectionProvider;
|
||||
import org.keycloak.models.map.userSession.MapUserSessionProviderFactory;
|
||||
import org.keycloak.models.sessions.infinispan.changes.sessions.CrossDCLastSessionRefreshStoreFactory;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.ResetTimeOffsetEvent;
|
||||
|
@ -238,6 +246,18 @@ public class TestingResourceProvider implements RealmResourceProvider {
|
|||
public Map<String, String> setTimeOffset(Map<String, String> time) {
|
||||
int offset = Integer.parseInt(time.get("offset"));
|
||||
|
||||
// move time on Hot Rod server if present
|
||||
// determine usage of Infinispan based on user sessions config
|
||||
String userSessionProvider = Config.scope(UserSessionSpi.NAME, MapUserSessionProviderFactory.PROVIDER_ID, AbstractMapProviderFactory.CONFIG_STORAGE).get("provider");
|
||||
if (Profile.isFeatureEnabled(Profile.Feature.MAP_STORAGE) && "hotrod".equals(userSessionProvider)) {
|
||||
RemoteCache<Object, Object> scriptCache = session.getProvider(HotRodConnectionProvider.class).getRemoteCache(DefaultHotRodConnectionProviderFactory.SCRIPT_CACHE);
|
||||
if (scriptCache != null) {
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("timeService", offset);
|
||||
scriptCache.execute("InfinispanTimeServiceTask", param);
|
||||
}
|
||||
}
|
||||
|
||||
Time.setOffset(offset);
|
||||
|
||||
// Time offset was restarted
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
org.keycloak.testsuite.model.infinispan.InfinispanTimeServiceTask
|
|
@ -327,6 +327,18 @@
|
|||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-testsuite-providers-to-base-testsuite</id>
|
||||
<phase>generate-test-resources</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includeGroupIds>org.keycloak.testsuite</includeGroupIds>
|
||||
<includeArtifactIds>integration-arquillian-testsuite-providers</includeArtifactIds>
|
||||
<outputDirectory>${project.build.directory}/lib</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
|
@ -957,6 +969,7 @@
|
|||
<keycloak.authEventsStore.map.storage.provider>hotrod</keycloak.authEventsStore.map.storage.provider>
|
||||
<keycloak.singleUseObject.map.storage.provider>hotrod</keycloak.singleUseObject.map.storage.provider>
|
||||
<infinispan.version>${infinispan.version}</infinispan.version>
|
||||
<project.version>${project.version}</project.version>
|
||||
<keycloak.testsuite.start-hotrod-container>${keycloak.testsuite.start-hotrod-container}</keycloak.testsuite.start-hotrod-container>
|
||||
<auth.server.quarkus.mapStorage.profile.config>hotrod</auth.server.quarkus.mapStorage.profile.config>
|
||||
<keycloak.globalLock.provider>hotrod</keycloak.globalLock.provider>
|
||||
|
|
|
@ -12,10 +12,11 @@ public class HotRodStoreTestEnricher {
|
|||
|
||||
public static final boolean HOT_ROD_START_CONTAINER = Boolean.parseBoolean(System.getProperty("keycloak.testsuite.start-hotrod-container", "false"));
|
||||
|
||||
private final InfinispanContainer hotRodContainer = new InfinispanContainer();
|
||||
private InfinispanContainer hotRodContainer;
|
||||
|
||||
public void beforeContainerStarted(@Observes(precedence = 1) StartSuiteContainers event) {
|
||||
if (!HOT_ROD_START_CONTAINER) return;
|
||||
hotRodContainer = new InfinispanContainer();
|
||||
hotRodContainer.start();
|
||||
|
||||
// Add env variable, so it can be picked up by Keycloak
|
||||
|
@ -24,6 +25,6 @@ public class HotRodStoreTestEnricher {
|
|||
|
||||
public void afterSuite(@Observes(precedence = 4) AfterSuite event) {
|
||||
if (!HOT_ROD_START_CONTAINER) return;
|
||||
hotRodContainer.stop();
|
||||
if (hotRodContainer != null) hotRodContainer.stop();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,11 @@ import org.jboss.logging.Logger;
|
|||
import org.keycloak.testsuite.arquillian.HotRodStoreTestEnricher;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.wait.strategy.Wait;
|
||||
import org.testcontainers.utility.MountableFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Duration;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
@ -50,6 +54,18 @@ public class InfinispanContainer extends GenericContainer<InfinispanContainer> {
|
|||
withEnv("USER", USERNAME);
|
||||
withEnv("PASS", PASSWORD);
|
||||
withNetworkMode("host");
|
||||
|
||||
Path dir = Path.of(Path.of("").toAbsolutePath() + "/target/lib");
|
||||
String projectVersion = System.getProperty("project.version");
|
||||
Path timeTaskPath;
|
||||
try {
|
||||
timeTaskPath = Files.find(dir, 1, (path, attr) -> path.toString()
|
||||
.endsWith("integration-arquillian-testsuite-providers-" + projectVersion + ".jar")).findFirst().orElse(null);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
MountableFile mountableFile = MountableFile.forHostPath(timeTaskPath, 0666);
|
||||
withCopyFileToContainer(mountableFile, "/opt/infinispan/server/lib/integration-arquillian-testsuite-providers.jar");
|
||||
|
||||
withStartupTimeout(Duration.ofMinutes(5));
|
||||
waitingFor(Wait.forLogMessage(".*Infinispan Server.*started in.*", 1));
|
||||
|
|
|
@ -644,6 +644,7 @@ public abstract class AbstractKeycloakTest {
|
|||
|
||||
/**
|
||||
* Sets time offset in seconds that will be added to Time.currentTime() and Time.currentTimeMillis() both for client and server.
|
||||
* Moves time on the remote Infinispan server as well if the HotRod storage is used.
|
||||
*
|
||||
* @param offset
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright 2023 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.admin;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.events.EventStoreProvider;
|
||||
import org.keycloak.events.EventStoreSpi;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.events.jpa.JpaEventStoreProviderFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class TimeOffsetTest extends AbstractAdminTest {
|
||||
|
||||
@Test
|
||||
public void testOffset() {
|
||||
String realmId = adminClient.realm(REALM_NAME).toRepresentation().getId();
|
||||
testingClient.server().run(session -> {
|
||||
RealmModel realm = session.realms().getRealmByName(REALM_NAME);
|
||||
realm.setEventsExpiration(5);
|
||||
EventStoreProvider provider = session.getProvider(EventStoreProvider.class);
|
||||
|
||||
Event e = new Event();
|
||||
e.setType(EventType.LOGIN);
|
||||
e.setTime(Time.currentTimeMillis());
|
||||
e.setRealmId(realmId);
|
||||
provider.onEvent(e);
|
||||
});
|
||||
|
||||
testingClient.server().run(session -> {
|
||||
EventStoreProvider provider = session.getProvider(EventStoreProvider.class);
|
||||
assertEquals(1, provider.createQuery().realm(realmId).getResultStream().count());
|
||||
});
|
||||
|
||||
setTimeOffset(5);
|
||||
|
||||
// legacy store requires manual trigger of expired events removal
|
||||
String eventStoreProvider = testingClient.server().fetch(session -> Config.getProvider(EventStoreSpi.NAME), String.class);
|
||||
if (eventStoreProvider.equals(JpaEventStoreProviderFactory.ID)) {
|
||||
testingClient.testing().clearExpiredEvents();
|
||||
}
|
||||
|
||||
testingClient.server().run(session -> {
|
||||
EventStoreProvider provider = session.getProvider(EventStoreProvider.class);
|
||||
assertEquals(0, provider.createQuery().realm(realmId).getResultStream().count());
|
||||
});
|
||||
}
|
||||
}
|
|
@ -179,6 +179,7 @@
|
|||
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
|
||||
<org.jboss.logging.provider>log4j</org.jboss.logging.provider>
|
||||
<infinispan.version>${infinispan.version}</infinispan.version>
|
||||
<project.version>${project.version}</project.version>
|
||||
</systemPropertyVariables>
|
||||
<properties>
|
||||
<property>
|
||||
|
@ -207,7 +208,24 @@
|
|||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-testsuite-providers-to-model-testsuite</id>
|
||||
<phase>generate-test-resources</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includeGroupIds>org.keycloak.testsuite</includeGroupIds>
|
||||
<includeArtifactIds>integration-arquillian-testsuite-providers</includeArtifactIds>
|
||||
<outputDirectory>${project.build.directory}/lib</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
package org.keycloak.testsuite.model;
|
||||
|
||||
import org.infinispan.client.hotrod.RemoteCache;
|
||||
import org.junit.Assert;
|
||||
import org.keycloak.Config.Scope;
|
||||
import org.keycloak.authorization.AuthorizationSpi;
|
||||
|
@ -45,6 +46,8 @@ import org.keycloak.models.DeploymentStateSpi;
|
|||
import org.keycloak.models.UserLoginFailureSpi;
|
||||
import org.keycloak.models.UserSessionSpi;
|
||||
import org.keycloak.models.UserSpi;
|
||||
import org.keycloak.models.map.storage.hotRod.connections.DefaultHotRodConnectionProviderFactory;
|
||||
import org.keycloak.models.map.storage.hotRod.connections.HotRodConnectionProvider;
|
||||
import org.keycloak.models.locking.GlobalLockProviderSpi;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.models.utils.PostMigrationEvent;
|
||||
|
@ -63,7 +66,7 @@ import java.lang.management.LockInfo;
|
|||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.ThreadInfo;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
@ -81,7 +84,6 @@ import java.util.concurrent.ThreadFactory;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
|
@ -527,17 +529,17 @@ public abstract class KeycloakModelTest {
|
|||
|
||||
@Before
|
||||
public final void createEnvironment() {
|
||||
Time.setOffset(0);
|
||||
setTimeOffset(0);
|
||||
USE_DEFAULT_FACTORY = isUseSameKeycloakSessionFactoryForAllThreads();
|
||||
KeycloakModelUtils.runJobInTransaction(getFactory(), this::createEnvironment);
|
||||
}
|
||||
|
||||
@After
|
||||
public final void cleanEnvironment() {
|
||||
Time.setOffset(0);
|
||||
if (getFactory() == null) {
|
||||
reinitializeKeycloakSessionFactory();
|
||||
}
|
||||
setTimeOffset(0);
|
||||
KeycloakModelUtils.runJobInTransaction(getFactory(), this::cleanEnvironment);
|
||||
}
|
||||
|
||||
|
@ -637,4 +639,24 @@ public abstract class KeycloakModelTest {
|
|||
return realm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves time on the Keycloak server as well as on the remote Infinispan server if the Infinispan is used.
|
||||
* @param seconds time offset in seconds by which Keycloak (and Infinispan) server time is moved
|
||||
*/
|
||||
protected void setTimeOffset(int seconds) {
|
||||
inComittedTransaction(session -> {
|
||||
// move time on Hot Rod server if present
|
||||
HotRodConnectionProvider hotRodConnectionProvider = session.getProvider(HotRodConnectionProvider.class);
|
||||
if (hotRodConnectionProvider != null) {
|
||||
RemoteCache<Object, Object> scriptCache = hotRodConnectionProvider.getRemoteCache(DefaultHotRodConnectionProviderFactory.SCRIPT_CACHE);
|
||||
if (scriptCache != null) {
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("timeService", seconds);
|
||||
Object returnFromTask = scriptCache.execute("InfinispanTimeServiceTask", param);
|
||||
LOG.info(returnFromTask);
|
||||
}
|
||||
}
|
||||
Time.setOffset(seconds);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ import org.jboss.logging.Logger;
|
|||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.common.Version;
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.connections.jpa.JpaConnectionProvider;
|
||||
import org.keycloak.migration.MigrationModel;
|
||||
import org.keycloak.migration.ModelVersion;
|
||||
|
@ -72,12 +71,12 @@ public class MigrationModelTest extends KeycloakModelTest {
|
|||
Assert.assertEquals(currentVersion, m.getStoredVersion());
|
||||
Assert.assertEquals(m.getResourcesTag(), l.get(0).getId());
|
||||
|
||||
Time.setOffset(-60000);
|
||||
setTimeOffset(-60000);
|
||||
|
||||
session.getProvider(DeploymentStateProvider.class).getMigrationModel().setStoredVersion("6.0.0");
|
||||
em.flush();
|
||||
|
||||
Time.setOffset(0);
|
||||
setTimeOffset(0);
|
||||
|
||||
l = em.createQuery("select m from MigrationModelEntity m ORDER BY m.updatedTime DESC", MigrationModelEntity.class).getResultList();
|
||||
Assert.assertEquals(2, l.size());
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright 2023 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.model;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.events.EventStoreProvider;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@RequireProvider(EventStoreProvider.class)
|
||||
public class TimeOffsetTest extends KeycloakModelTest {
|
||||
|
||||
private String realmId;
|
||||
|
||||
@Override
|
||||
protected void createEnvironment(KeycloakSession s) {
|
||||
RealmModel r = s.realms().createRealm("realm");
|
||||
r.setDefaultRole(s.roles().addRealmRole(r, Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + r.getName()));
|
||||
r.setEventsExpiration(5);
|
||||
realmId = r.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanEnvironment(KeycloakSession s) {
|
||||
s.realms().removeRealm(realmId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOffset() {
|
||||
withRealm(realmId, (session, realmModel) -> {
|
||||
EventStoreProvider provider = session.getProvider(EventStoreProvider.class);
|
||||
|
||||
Event e = new Event();
|
||||
e.setType(EventType.LOGIN);
|
||||
e.setRealmId(realmId);
|
||||
e.setTime(Time.currentTimeMillis());
|
||||
provider.onEvent(e);
|
||||
return null;
|
||||
});
|
||||
|
||||
withRealm(realmId, (session, realmModel) -> {
|
||||
EventStoreProvider provider = session.getProvider(EventStoreProvider.class);
|
||||
assertEquals(1, provider.createQuery().realm(realmId).getResultStream().count());
|
||||
|
||||
setTimeOffset(5);
|
||||
|
||||
// legacy store requires explicit expiration of expired events
|
||||
ProviderFactory<EventStoreProvider> providerFactory = session.getKeycloakSessionFactory().getProviderFactory(EventStoreProvider.class);
|
||||
if ("jpa".equals(providerFactory.getId())) {
|
||||
provider.clearExpiredEvents();
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
withRealm(realmId, (session, realmModel) -> {
|
||||
EventStoreProvider provider = session.getProvider(EventStoreProvider.class);
|
||||
assertEquals(0, provider.createQuery().realm(realmId).getResultStream().count());
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -17,7 +17,6 @@
|
|||
package org.keycloak.testsuite.model.events;
|
||||
|
||||
import org.keycloak.common.ClientConnection;
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.events.EventBuilder;
|
||||
import org.keycloak.events.EventStoreProvider;
|
||||
|
@ -159,7 +158,7 @@ public class EventQueryTest extends KeycloakModelTest {
|
|||
return null;
|
||||
});
|
||||
|
||||
Time.setOffset(10);
|
||||
setTimeOffset(10);
|
||||
|
||||
try {
|
||||
withRealm(realmId, (session, realm) -> {
|
||||
|
@ -173,7 +172,7 @@ public class EventQueryTest extends KeycloakModelTest {
|
|||
return null;
|
||||
});
|
||||
} finally {
|
||||
Time.setOffset(0);
|
||||
setTimeOffset(0);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ package org.keycloak.testsuite.model.session;
|
|||
import org.hamcrest.Matchers;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
@ -72,7 +71,7 @@ public class AuthenticationSessionTest extends KeycloakModelTest {
|
|||
ClientModel client = realm.getClientByClientId("test-app");
|
||||
return IntStream.range(0, 300)
|
||||
.mapToObj(i -> {
|
||||
Time.setOffset(i);
|
||||
setTimeOffset(i);
|
||||
return ras.createAuthenticationSession(client);
|
||||
})
|
||||
.map(AuthenticationSessionModel::getTabId)
|
||||
|
@ -184,7 +183,7 @@ public class AuthenticationSessionTest extends KeycloakModelTest {
|
|||
RootAuthenticationSessionModel rootAuthSession = session.authenticationSessions().getRootAuthenticationSession(realm, rootAuthSessionId.get());
|
||||
Assert.assertNotNull(rootAuthSession);
|
||||
|
||||
Time.setOffset(1900);
|
||||
setTimeOffset(1900);
|
||||
|
||||
return null;
|
||||
});
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
package org.keycloak.testsuite.model.session;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
@ -67,9 +66,8 @@ public class UserSessionExpirationTest extends KeycloakModelTest {
|
|||
|
||||
assertThat(withRealm(realmId, (session, realm) -> session.sessions().getUserSession(realm, uSId)), notNullValue());
|
||||
|
||||
Time.setOffset(5);
|
||||
setTimeOffset(5);
|
||||
|
||||
assertThat(withRealm(realmId, (session, realm) -> session.sessions().getUserSession(realm, uSId)), nullValue());
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -432,7 +432,7 @@ public class UserSessionPersisterProviderTest extends KeycloakModelTest {
|
|||
|
||||
for (int i = 0; i < USER_SESSION_COUNT; i++) {
|
||||
// Having different offsets for each session (to ensure that lastSessionRefresh is also different)
|
||||
Time.setOffset(i);
|
||||
setTimeOffset(i);
|
||||
|
||||
UserSessionModel userSession = session.sessions().createUserSession(realm, user, "user1", "127.0.0.1", "form", true, null, null);
|
||||
createClientSession(session, realmId, realm.getClientByClientId("test-app"), userSession, "http://redirect", "state");
|
||||
|
@ -464,6 +464,7 @@ public class UserSessionPersisterProviderTest extends KeycloakModelTest {
|
|||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -495,7 +496,7 @@ public class UserSessionPersisterProviderTest extends KeycloakModelTest {
|
|||
persister.updateLastSessionRefreshes(realm, lastSessionRefresh, Collections.singleton(userSession1[0].getId()), true);
|
||||
|
||||
// Increase time offset - 40 days
|
||||
Time.setOffset(3456000);
|
||||
setTimeOffset(3456000);
|
||||
try {
|
||||
// Run expiration thread
|
||||
persister.removeExpired(realm);
|
||||
|
@ -507,7 +508,7 @@ public class UserSessionPersisterProviderTest extends KeycloakModelTest {
|
|||
|
||||
} finally {
|
||||
// Cleanup
|
||||
Time.setOffset(0);
|
||||
setTimeOffset(0);
|
||||
session.getKeycloakSessionFactory().publish(new ResetTimeOffsetEvent());
|
||||
}
|
||||
});
|
||||
|
|
|
@ -20,7 +20,6 @@ import org.hamcrest.Matchers;
|
|||
import org.infinispan.client.hotrod.RemoteCache;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.models.AuthenticatedClientSessionModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.Constants;
|
||||
|
@ -193,7 +192,7 @@ public class UserSessionProviderModelTest extends KeycloakModelTest {
|
|||
clientSession.setTimestamp(1);
|
||||
});
|
||||
} else {
|
||||
Time.setOffset(1000);
|
||||
setTimeOffset(1000);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -211,7 +210,7 @@ public class UserSessionProviderModelTest extends KeycloakModelTest {
|
|||
});
|
||||
});
|
||||
} finally {
|
||||
Time.setOffset(0);
|
||||
setTimeOffset(0);
|
||||
kcSession.getKeycloakSessionFactory().publish(new ResetTimeOffsetEvent());
|
||||
if (timer != null && timerTaskCtx != null) {
|
||||
timer.schedule(timerTaskCtx.getRunnable(), timerTaskCtx.getIntervalMillis(), PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME);
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
package org.keycloak.testsuite.model.session;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.infinispan.Cache;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Assume;
|
||||
|
@ -51,9 +50,7 @@ import java.util.Map;
|
|||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
|
@ -163,7 +160,7 @@ public class UserSessionProviderOfflineModelTest extends KeycloakModelTest {
|
|||
// sessions are in persister too
|
||||
Assert.assertEquals(3, persister.getUserSessionsCount(true));
|
||||
|
||||
Time.setOffset(300);
|
||||
setTimeOffset(300);
|
||||
log.infof("Set time offset to 300. Time is: %d", Time.currentTime());
|
||||
|
||||
// Set lastSessionRefresh to currentSession[0] to 0
|
||||
|
@ -178,7 +175,7 @@ public class UserSessionProviderOfflineModelTest extends KeycloakModelTest {
|
|||
int timeOffset = 1728000 + (i * 86400);
|
||||
|
||||
RealmModel realm = session.realms().getRealm(realmId);
|
||||
Time.setOffset(timeOffset);
|
||||
setTimeOffset(timeOffset);
|
||||
log.infof("Set time offset to %d. Time is: %d", timeOffset, Time.currentTime());
|
||||
|
||||
UserSessionModel session0 = session.sessions().getOfflineUserSession(realm, origSessions[0].getId());
|
||||
|
@ -192,7 +189,7 @@ public class UserSessionProviderOfflineModelTest extends KeycloakModelTest {
|
|||
persister = session.getProvider(UserSessionPersisterProvider.class);
|
||||
|
||||
// Increase timeOffset - 40 days
|
||||
Time.setOffset(3456000);
|
||||
setTimeOffset(3456000);
|
||||
log.infof("Set time offset to 3456000. Time is: %d", Time.currentTime());
|
||||
|
||||
// Expire and ensure that all sessions despite session0 were removed
|
||||
|
@ -211,7 +208,7 @@ public class UserSessionProviderOfflineModelTest extends KeycloakModelTest {
|
|||
Assert.assertEquals(1, persister.getUserSessionsCount(true));
|
||||
|
||||
// Expire everything and assert nothing found
|
||||
Time.setOffset(7000000);
|
||||
setTimeOffset(7000000);
|
||||
|
||||
persister.removeExpired(realm);
|
||||
});
|
||||
|
@ -228,7 +225,7 @@ public class UserSessionProviderOfflineModelTest extends KeycloakModelTest {
|
|||
});
|
||||
|
||||
} finally {
|
||||
Time.setOffset(0);
|
||||
setTimeOffset(0);
|
||||
kcSession.getKeycloakSessionFactory().publish(new ResetTimeOffsetEvent());
|
||||
if (timer != null) {
|
||||
timer.schedule(timerTaskCtx.getRunnable(), timerTaskCtx.getIntervalMillis(), PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME);
|
||||
|
@ -278,7 +275,7 @@ public class UserSessionProviderOfflineModelTest extends KeycloakModelTest {
|
|||
persister = session.getProvider(UserSessionPersisterProvider.class);
|
||||
|
||||
// Expire everything except offline client sessions
|
||||
Time.setOffset(7000000);
|
||||
setTimeOffset(7000000);
|
||||
|
||||
persister.removeExpired(realm);
|
||||
});
|
||||
|
@ -300,7 +297,7 @@ public class UserSessionProviderOfflineModelTest extends KeycloakModelTest {
|
|||
});
|
||||
|
||||
} finally {
|
||||
Time.setOffset(0);
|
||||
setTimeOffset(0);
|
||||
kcSession.getKeycloakSessionFactory().publish(new ResetTimeOffsetEvent());
|
||||
if (timer != null) {
|
||||
timer.schedule(timerTaskCtx.getRunnable(), timerTaskCtx.getIntervalMillis(), PersisterLastSessionRefreshStoreFactory.DB_LSR_PERIODIC_TASK_NAME);
|
||||
|
|
|
@ -60,7 +60,6 @@ public class SingleUseObjectModelTest extends KeycloakModelTest {
|
|||
|
||||
@Override
|
||||
public void cleanEnvironment(KeycloakSession s) {
|
||||
Time.setOffset(0);
|
||||
s.realms().removeRealm(realmId);
|
||||
}
|
||||
|
||||
|
@ -103,7 +102,7 @@ public class SingleUseObjectModelTest extends KeycloakModelTest {
|
|||
Assert.assertNotNull(notes);
|
||||
Assert.assertEquals("bar", notes.get("foo"));
|
||||
|
||||
Time.setOffset(70);
|
||||
setTimeOffset(70);
|
||||
|
||||
notes = singleUseObjectProvider.get(key.serializeKey());
|
||||
Assert.assertNull(notes);
|
||||
|
@ -154,7 +153,7 @@ public class SingleUseObjectModelTest extends KeycloakModelTest {
|
|||
Map<String, String> actualNotes = singleUseStore.get(key);
|
||||
assertThat(actualNotes, Matchers.anEmptyMap());
|
||||
|
||||
Time.setOffset(70);
|
||||
setTimeOffset(70);
|
||||
|
||||
Assert.assertNull(singleUseStore.get(key));
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue