|
|
|
@ -1,5 +1,5 @@ |
|
|
|
/* |
|
|
|
/* |
|
|
|
* Copyright 2002-2024 the original author or authors. |
|
|
|
* Copyright 2002-2025 the original author or authors. |
|
|
|
* |
|
|
|
* |
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
|
* you may not use this file except in compliance with the License. |
|
|
|
* you may not use this file except in compliance with the License. |
|
|
|
@ -19,7 +19,6 @@ package org.springframework.web.server.session; |
|
|
|
import java.time.Clock; |
|
|
|
import java.time.Clock; |
|
|
|
import java.time.Duration; |
|
|
|
import java.time.Duration; |
|
|
|
import java.time.Instant; |
|
|
|
import java.time.Instant; |
|
|
|
import java.util.Map; |
|
|
|
|
|
|
|
import java.util.stream.IntStream; |
|
|
|
import java.util.stream.IntStream; |
|
|
|
|
|
|
|
|
|
|
|
import org.junit.jupiter.api.Test; |
|
|
|
import org.junit.jupiter.api.Test; |
|
|
|
@ -35,10 +34,11 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException; |
|
|
|
* Tests for {@link InMemoryWebSessionStore}. |
|
|
|
* Tests for {@link InMemoryWebSessionStore}. |
|
|
|
* |
|
|
|
* |
|
|
|
* @author Rob Winch |
|
|
|
* @author Rob Winch |
|
|
|
|
|
|
|
* @author Sam Brannen |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
class InMemoryWebSessionStoreTests { |
|
|
|
class InMemoryWebSessionStoreTests { |
|
|
|
|
|
|
|
|
|
|
|
private InMemoryWebSessionStore store = new InMemoryWebSessionStore(); |
|
|
|
private final InMemoryWebSessionStore store = new InMemoryWebSessionStore(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
@Test |
|
|
|
@ -59,7 +59,7 @@ class InMemoryWebSessionStoreTests { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Test // gh-24027, gh-26958
|
|
|
|
@Test // gh-24027, gh-26958
|
|
|
|
public void createSessionDoesNotBlock() { |
|
|
|
void createSessionDoesNotBlock() { |
|
|
|
this.store.createWebSession() |
|
|
|
this.store.createWebSession() |
|
|
|
.doOnNext(session -> assertThat(Schedulers.isInNonBlockingThread()).isTrue()) |
|
|
|
.doOnNext(session -> assertThat(Schedulers.isInNonBlockingThread()).isTrue()) |
|
|
|
.block(); |
|
|
|
.block(); |
|
|
|
@ -103,7 +103,7 @@ class InMemoryWebSessionStoreTests { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Test // SPR-17051
|
|
|
|
@Test // SPR-17051
|
|
|
|
public void sessionInvalidatedBeforeSave() { |
|
|
|
void sessionInvalidatedBeforeSave() { |
|
|
|
// Request 1 creates session
|
|
|
|
// Request 1 creates session
|
|
|
|
WebSession session1 = this.store.createWebSession().block(); |
|
|
|
WebSession session1 = this.store.createWebSession().block(); |
|
|
|
assertThat(session1).isNotNull(); |
|
|
|
assertThat(session1).isNotNull(); |
|
|
|
@ -132,33 +132,31 @@ class InMemoryWebSessionStoreTests { |
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
@Test |
|
|
|
void expirationCheckPeriod() { |
|
|
|
void expirationCheckPeriod() { |
|
|
|
|
|
|
|
|
|
|
|
DirectFieldAccessor accessor = new DirectFieldAccessor(this.store); |
|
|
|
|
|
|
|
Map<?,?> sessions = (Map<?, ?>) accessor.getPropertyValue("sessions"); |
|
|
|
|
|
|
|
assertThat(sessions).isNotNull(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create 100 sessions
|
|
|
|
// Create 100 sessions
|
|
|
|
IntStream.range(0, 100).forEach(i -> insertSession()); |
|
|
|
IntStream.rangeClosed(1, 100).forEach(i -> insertSession()); |
|
|
|
assertThat(sessions).hasSize(100); |
|
|
|
assertNumSessions(100); |
|
|
|
|
|
|
|
|
|
|
|
// Force a new clock (31 min later), don't use setter which would clean expired sessions
|
|
|
|
// Force a new clock (31 min later). Don't use setter which would clean expired sessions.
|
|
|
|
|
|
|
|
DirectFieldAccessor accessor = new DirectFieldAccessor(this.store); |
|
|
|
accessor.setPropertyValue("clock", Clock.offset(this.store.getClock(), Duration.ofMinutes(31))); |
|
|
|
accessor.setPropertyValue("clock", Clock.offset(this.store.getClock(), Duration.ofMinutes(31))); |
|
|
|
assertThat(sessions).hasSize(100); |
|
|
|
assertNumSessions(100); |
|
|
|
|
|
|
|
|
|
|
|
// Create 1 more which forces a time-based check (clock moved forward)
|
|
|
|
// Create 1 more which forces a time-based check (clock moved forward).
|
|
|
|
insertSession(); |
|
|
|
insertSession(); |
|
|
|
assertThat(sessions).hasSize(1); |
|
|
|
assertNumSessions(1); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
@Test |
|
|
|
void maxSessions() { |
|
|
|
void maxSessions() { |
|
|
|
|
|
|
|
this.store.setMaxSessions(10); |
|
|
|
|
|
|
|
|
|
|
|
IntStream.range(0, 10000).forEach(i -> insertSession()); |
|
|
|
IntStream.rangeClosed(1, 10).forEach(i -> insertSession()); |
|
|
|
assertThatIllegalStateException().isThrownBy( |
|
|
|
assertThatIllegalStateException() |
|
|
|
this::insertSession) |
|
|
|
.isThrownBy(this::insertSession) |
|
|
|
.withMessage("Max sessions limit reached: 10000"); |
|
|
|
.withMessage("Max sessions limit reached: 10"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private WebSession insertSession() { |
|
|
|
private WebSession insertSession() { |
|
|
|
WebSession session = this.store.createWebSession().block(); |
|
|
|
WebSession session = this.store.createWebSession().block(); |
|
|
|
assertThat(session).isNotNull(); |
|
|
|
assertThat(session).isNotNull(); |
|
|
|
@ -167,4 +165,8 @@ class InMemoryWebSessionStoreTests { |
|
|
|
return session; |
|
|
|
return session; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void assertNumSessions(int numSessions) { |
|
|
|
|
|
|
|
assertThat(store.getSessions()).hasSize(numSessions); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|