Polish "Add WebFlux Support"
Closes gh-683
This commit is contained in:
@@ -7,14 +7,14 @@ dependencies {
|
||||
|
||||
optional "io.projectreactor:reactor-core"
|
||||
optional "javax.servlet:javax.servlet-api"
|
||||
optional "org.springframework.security:spring-security-core"
|
||||
optional "org.springframework.security:spring-security-web"
|
||||
optional "org.springframework:spring-context"
|
||||
optional "org.springframework:spring-jdbc"
|
||||
optional "org.springframework:spring-messaging"
|
||||
optional "org.springframework:spring-web"
|
||||
optional "org.springframework:spring-webflux"
|
||||
optional "org.springframework:spring-websocket"
|
||||
optional "org.springframework.security:spring-security-core"
|
||||
optional "org.springframework.security:spring-security-web"
|
||||
|
||||
testCompile "io.projectreactor:reactor-test"
|
||||
testCompile "junit:junit"
|
||||
|
||||
@@ -16,6 +16,14 @@
|
||||
|
||||
package org.springframework.session.web.server.session;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.List;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.session.ReactorSessionRepository;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -25,33 +33,39 @@ import org.springframework.web.server.session.CookieWebSessionIdResolver;
|
||||
import org.springframework.web.server.session.WebSessionIdResolver;
|
||||
import org.springframework.web.server.session.WebSessionManager;
|
||||
import org.springframework.web.server.session.WebSessionStore;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The {@link WebSessionManager} implementation backed by
|
||||
* {@link ReactorSessionRepository}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 2.0
|
||||
*/
|
||||
public class SpringSessionWebSessionManager implements WebSessionManager {
|
||||
|
||||
private final SpringSessionWebSessionStore<? extends Session> sessionStore;
|
||||
|
||||
private WebSessionIdResolver sessionIdResolver = new CookieWebSessionIdResolver();
|
||||
|
||||
private Clock clock = Clock.system(ZoneId.of("GMT"));
|
||||
private Clock clock = Clock.system(ZoneOffset.UTC);
|
||||
|
||||
public SpringSessionWebSessionManager(ReactorSessionRepository<? extends Session> sessionRepository) {
|
||||
sessionStore
|
||||
= new SpringSessionWebSessionStore<>(sessionRepository);
|
||||
public SpringSessionWebSessionManager(
|
||||
ReactorSessionRepository<? extends Session> sessionRepository) {
|
||||
this.sessionStore = new SpringSessionWebSessionStore<>(sessionRepository);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configured {@link WebSessionIdResolver}.
|
||||
* @return the configured {@link WebSessionIdResolver}
|
||||
*/
|
||||
private WebSessionIdResolver getSessionIdResolver() {
|
||||
return this.sessionIdResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the id resolution strategy.
|
||||
* <p>By default an instance of {@link CookieWebSessionIdResolver}.
|
||||
* <p>
|
||||
* By default an instance of {@link CookieWebSessionIdResolver}.
|
||||
* @param sessionIdResolver the resolver to use
|
||||
*/
|
||||
public void setSessionIdResolver(WebSessionIdResolver sessionIdResolver) {
|
||||
@@ -59,27 +73,31 @@ public class SpringSessionWebSessionManager implements WebSessionManager {
|
||||
this.sessionIdResolver = sessionIdResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configured {@link WebSessionIdResolver}.
|
||||
*/
|
||||
private WebSessionIdResolver getSessionIdResolver() {
|
||||
return this.sessionIdResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configured {@link WebSessionStore}.
|
||||
* @return the configured {@link WebSessionStore}
|
||||
*/
|
||||
private WebSessionStore getSessionStore() {
|
||||
return this.sessionStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the {@link Clock} to use to set lastAccessTime on every created
|
||||
* session and to calculate if it is expired.
|
||||
* <p>This may be useful to align to different timezone or to set the clock
|
||||
* back in a test, e.g. {@code Clock.offset(clock, Duration.ofMinutes(-31))}
|
||||
* in order to simulate session expiration.
|
||||
* <p>By default this is {@code Clock.system(ZoneId.of("GMT"))}.
|
||||
* Return the configured clock for session {@code lastAccessTime} calculations.
|
||||
* @return the configured clock for session {@code lastAccessTime} calculations
|
||||
*/
|
||||
private Clock getClock() {
|
||||
return this.clock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the {@link Clock} to use to set lastAccessTime on every created session
|
||||
* and to calculate if it is expired.
|
||||
* <p>
|
||||
* This may be useful to align to different timezone or to set the clock back in a
|
||||
* test, e.g. {@code Clock.offset(clock, Duration.ofMinutes(-31))} in order to
|
||||
* simulate session expiration.
|
||||
* <p>
|
||||
* By default this is {@code Clock.system(ZoneOffset.UTC)}.
|
||||
* @param clock the clock to use
|
||||
*/
|
||||
public void setClock(Clock clock) {
|
||||
@@ -87,15 +105,9 @@ public class SpringSessionWebSessionManager implements WebSessionManager {
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configured clock for session lastAccessTime calculations.
|
||||
*/
|
||||
private Clock getClock() {
|
||||
return this.clock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<WebSession> getSession(ServerWebExchange exchange) {
|
||||
// @formatter:off
|
||||
return Mono.defer(() ->
|
||||
retrieveSession(exchange)
|
||||
.flatMap(session -> removeSessionIfExpired(exchange, session))
|
||||
@@ -105,16 +117,20 @@ public class SpringSessionWebSessionManager implements WebSessionManager {
|
||||
})
|
||||
.switchIfEmpty(createSession(exchange))
|
||||
.doOnNext(session -> exchange.getResponse().beforeCommit(session::save)));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private Mono<WebSession> retrieveSession(ServerWebExchange exchange) {
|
||||
// @formatter:off
|
||||
return Flux.fromIterable(getSessionIdResolver().resolveSessionIds(exchange))
|
||||
.concatMap(this.sessionStore::retrieveSession)
|
||||
.cast(WebSession.class)
|
||||
.next();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private Mono<WebSession> removeSessionIfExpired(ServerWebExchange exchange, WebSession session) {
|
||||
private Mono<WebSession> removeSessionIfExpired(ServerWebExchange exchange,
|
||||
WebSession session) {
|
||||
if (session.isExpired()) {
|
||||
this.sessionIdResolver.expireSession(exchange);
|
||||
return this.sessionStore.removeSession(session.getId()).then(Mono.empty());
|
||||
@@ -125,10 +141,10 @@ public class SpringSessionWebSessionManager implements WebSessionManager {
|
||||
private Mono<Void> saveSession(ServerWebExchange exchange, WebSession session) {
|
||||
if (session.isExpired()) {
|
||||
return Mono.error(new IllegalStateException(
|
||||
"Sessions are checked for expiration and have their " +
|
||||
"lastAccessTime updated when first accessed during request processing. " +
|
||||
"However this session is expired meaning that maxIdleTime elapsed " +
|
||||
"before the call to session.save()."));
|
||||
"Sessions are checked for expiration and have their "
|
||||
+ "lastAccessTime updated when first accessed during request processing. "
|
||||
+ "However this session is expired meaning that maxIdleTime elapsed "
|
||||
+ "before the call to session.save()."));
|
||||
}
|
||||
|
||||
if (!session.isStarted()) {
|
||||
@@ -153,4 +169,5 @@ public class SpringSessionWebSessionManager implements WebSessionManager {
|
||||
private Mono<WebSession> createSession(ServerWebExchange exchange) {
|
||||
return this.sessionStore.createSession();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,25 +16,39 @@
|
||||
|
||||
package org.springframework.session.web.server.session;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.session.ReactorSessionRepository;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.server.WebSession;
|
||||
import org.springframework.web.server.session.WebSessionStore;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* The {@link WebSessionStore} implementation that provides the {@link WebSession}
|
||||
* implementation backed by a {@link Session} returned by the
|
||||
* {@link ReactorSessionRepository}.
|
||||
*
|
||||
* @param <S> the {@link Session} type
|
||||
* @author Rob Winch
|
||||
* @since 2.0
|
||||
*/
|
||||
class SpringSessionWebSessionStore<S extends Session> implements WebSessionStore {
|
||||
|
||||
private final ReactorSessionRepository<S> sessions;
|
||||
|
||||
SpringSessionWebSessionStore(ReactorSessionRepository<S> sessions) {
|
||||
@@ -48,6 +62,7 @@ class SpringSessionWebSessionStore<S extends Session> implements WebSessionStore
|
||||
|
||||
public Mono<WebSession> setLastAccessedTime(WebSession session,
|
||||
Instant lastAccessedTime) {
|
||||
@SuppressWarnings("unchecked")
|
||||
SpringSessionWebSession springSessionWebSession = (SpringSessionWebSession) session;
|
||||
springSessionWebSession.session.setLastAccessedTime(lastAccessedTime);
|
||||
return Mono.just(session);
|
||||
@@ -80,92 +95,17 @@ class SpringSessionWebSessionStore<S extends Session> implements WebSessionStore
|
||||
|
||||
@Override
|
||||
public Mono<Void> removeSession(String sessionId) {
|
||||
return sessions.delete(sessionId);
|
||||
}
|
||||
|
||||
private class SpringSessionWebSession implements WebSession {
|
||||
private final S session;
|
||||
|
||||
private final Map<String, Object> attributes;
|
||||
|
||||
private AtomicReference<State> state = new AtomicReference<>();
|
||||
|
||||
private volatile transient Supplier<Mono<Void>> saveOperation = Mono::empty;
|
||||
|
||||
SpringSessionWebSession(S session, State state) {
|
||||
Assert.notNull(session, "session cannot be null");
|
||||
this.session = session;
|
||||
this.attributes = new SpringSessionMap(session);
|
||||
this.state.set(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return session.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> changeSessionId() {
|
||||
return Mono.defer(() -> {
|
||||
session.changeSessionId();
|
||||
return save();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getAttributes() {
|
||||
return this.attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
this.state.compareAndSet(State.NEW, State.STARTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStarted() {
|
||||
State value = this.state.get();
|
||||
return (State.STARTED.equals(value)
|
||||
|| (State.NEW.equals(value) && !getAttributes().isEmpty()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> save() {
|
||||
return this.saveOperation.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExpired() {
|
||||
return this.session.isExpired();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant getCreationTime() {
|
||||
return this.session.getCreationTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant getLastAccessTime() {
|
||||
return this.session.getLastAccessedTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxIdleTime(Duration maxIdleTime) {
|
||||
this.session.setMaxInactiveInterval(maxIdleTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration getMaxIdleTime() {
|
||||
return this.session.getMaxInactiveInterval();
|
||||
}
|
||||
return this.sessions.delete(sessionId);
|
||||
}
|
||||
|
||||
private enum State {
|
||||
NEW, STARTED
|
||||
}
|
||||
|
||||
static class SpringSessionMap implements Map<String, Object> {
|
||||
private static class SpringSessionMap implements Map<String, Object> {
|
||||
|
||||
private final Session session;
|
||||
|
||||
private final Collection<Object> values = new SessionValues();
|
||||
|
||||
SpringSessionMap(Session session) {
|
||||
@@ -243,7 +183,7 @@ class SpringSessionWebSessionStore<S extends Session> implements WebSessionStore
|
||||
|
||||
@Override
|
||||
public Collection<Object> values() {
|
||||
return values;
|
||||
return this.values;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -258,21 +198,24 @@ class SpringSessionWebSessionStore<S extends Session> implements WebSessionStore
|
||||
}
|
||||
|
||||
private class SessionValues extends AbstractCollection<Object> {
|
||||
|
||||
public Iterator<Object> iterator() {
|
||||
return new Iterator<Object>() {
|
||||
|
||||
private Iterator<Entry<String, Object>> i = entrySet().iterator();
|
||||
|
||||
public boolean hasNext() {
|
||||
return i.hasNext();
|
||||
return this.i.hasNext();
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
return i.next().getValue();
|
||||
return this.i.next().getValue();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
i.remove();
|
||||
this.i.remove();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -291,6 +234,91 @@ class SpringSessionWebSessionStore<S extends Session> implements WebSessionStore
|
||||
public boolean contains(Object v) {
|
||||
return SpringSessionMap.this.containsValue(v);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts Spring Session's {@link Session} to a {@link WebSession}.
|
||||
*/
|
||||
private class SpringSessionWebSession implements WebSession {
|
||||
|
||||
private final S session;
|
||||
|
||||
private final Map<String, Object> attributes;
|
||||
|
||||
private AtomicReference<State> state = new AtomicReference<>();
|
||||
|
||||
private volatile transient Supplier<Mono<Void>> saveOperation = Mono::empty;
|
||||
|
||||
SpringSessionWebSession(S session, State state) {
|
||||
Assert.notNull(session, "session cannot be null");
|
||||
this.session = session;
|
||||
this.attributes = new SpringSessionMap(session);
|
||||
this.state.set(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return this.session.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> changeSessionId() {
|
||||
return Mono.defer(() -> {
|
||||
this.session.changeSessionId();
|
||||
return save();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getAttributes() {
|
||||
return this.attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
this.state.compareAndSet(State.NEW, State.STARTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStarted() {
|
||||
State value = this.state.get();
|
||||
return (State.STARTED.equals(value)
|
||||
|| (State.NEW.equals(value) && !getAttributes().isEmpty()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> save() {
|
||||
return this.saveOperation.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExpired() {
|
||||
return this.session.isExpired();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant getCreationTime() {
|
||||
return this.session.getCreationTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant getLastAccessTime() {
|
||||
return this.session.getLastAccessedTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration getMaxIdleTime() {
|
||||
return this.session.getMaxInactiveInterval();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxIdleTime(Duration maxIdleTime) {
|
||||
this.session.setMaxInactiveInterval(maxIdleTime);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,23 @@
|
||||
/*
|
||||
* Copyright 2014-2017 the original author or authors.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
* Spring Session reactive web support.
|
||||
*/
|
||||
@NonNullApi
|
||||
package org.springframework.session.web.server.session;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullApi;
|
||||
|
||||
@@ -16,11 +16,18 @@
|
||||
|
||||
package org.springframework.session.web.server.session;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.http.HttpCookie;
|
||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
||||
import org.springframework.session.ReactorSessionRepository;
|
||||
@@ -28,49 +35,45 @@ import org.springframework.session.Session;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebSession;
|
||||
import org.springframework.web.server.session.WebSessionIdResolver;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Tests for {@link SpringSessionWebSessionManager}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class SpringSessionWebSessionManagerTests<S extends Session> {
|
||||
@Mock
|
||||
ReactorSessionRepository<S> sessions;
|
||||
|
||||
@Mock
|
||||
WebSessionIdResolver resolver;
|
||||
private ReactorSessionRepository<S> sessions;
|
||||
|
||||
@Mock
|
||||
S createSession;
|
||||
private WebSessionIdResolver resolver;
|
||||
|
||||
@Mock
|
||||
S findByIdSession;
|
||||
private S createSession;
|
||||
|
||||
Mono<S> createSessionMono;
|
||||
@Mock
|
||||
private S findByIdSession;
|
||||
|
||||
ServerWebExchange exchange = MockServerHttpRequest.get("/").toExchange();
|
||||
private Mono<S> createSessionMono;
|
||||
|
||||
private ServerWebExchange exchange = MockServerHttpRequest.get("/").toExchange();
|
||||
|
||||
SpringSessionWebSessionManager manager;
|
||||
private SpringSessionWebSessionManager manager;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
when(this.createSession.getId()).thenReturn("createSession-id");
|
||||
when(this.findByIdSession.getId()).thenReturn("findByIdSession-id");
|
||||
given(this.createSession.getId()).willReturn("createSession-id");
|
||||
given(this.findByIdSession.getId()).willReturn("findByIdSession-id");
|
||||
this.createSessionMono = Mono.just(this.createSession);
|
||||
when(this.sessions.createSession()).thenReturn(createSessionMono);
|
||||
given(this.sessions.createSession()).willReturn(this.createSessionMono);
|
||||
this.manager = new SpringSessionWebSessionManager(this.sessions);
|
||||
this.manager.setSessionIdResolver(this.resolver);
|
||||
}
|
||||
@@ -78,11 +81,13 @@ public class SpringSessionWebSessionManagerTests<S extends Session> {
|
||||
@Test
|
||||
public void getSessionWhenDefaultSessionIdResolverFoundSessionUsed() {
|
||||
String findByIdSessionId = this.findByIdSession.getId();
|
||||
this.exchange = MockServerHttpRequest.get("/").cookie(new HttpCookie("SESSION", findByIdSessionId)).toExchange();
|
||||
this.exchange = MockServerHttpRequest.get("/")
|
||||
.cookie(new HttpCookie("SESSION", findByIdSessionId)).toExchange();
|
||||
this.manager = new SpringSessionWebSessionManager(this.sessions);
|
||||
when(this.sessions.findById(findByIdSessionId)).thenReturn(Mono.just(findByIdSession));
|
||||
given(this.sessions.findById(findByIdSessionId))
|
||||
.willReturn(Mono.just(this.findByIdSession));
|
||||
|
||||
WebSession webSession = this.manager.getSession(exchange).block();
|
||||
WebSession webSession = this.manager.getSession(this.exchange).block();
|
||||
|
||||
assertThat(webSession.getId()).isEqualTo(findByIdSessionId);
|
||||
verify(this.sessions).findById(findByIdSessionId);
|
||||
@@ -90,7 +95,7 @@ public class SpringSessionWebSessionManagerTests<S extends Session> {
|
||||
|
||||
@Test
|
||||
public void getSessionWhenNewThenCreateSessionInvoked() {
|
||||
WebSession webSession = this.manager.getSession(exchange).block();
|
||||
WebSession webSession = this.manager.getSession(this.exchange).block();
|
||||
|
||||
assertThat(webSession.getId()).isEqualTo(this.createSession.getId());
|
||||
verify(this.sessions).createSession();
|
||||
@@ -101,7 +106,7 @@ public class SpringSessionWebSessionManagerTests<S extends Session> {
|
||||
String attrName = "attrName";
|
||||
String attrValue = "attrValue";
|
||||
|
||||
WebSession webSession = this.manager.getSession(exchange).block();
|
||||
WebSession webSession = this.manager.getSession(this.exchange).block();
|
||||
webSession.getAttributes().put(attrName, attrValue);
|
||||
|
||||
verify(this.createSession).setAttribute(attrName, attrValue);
|
||||
@@ -111,29 +116,31 @@ public class SpringSessionWebSessionManagerTests<S extends Session> {
|
||||
public void getSessionWhenInvalidIdThenCreateSessionInvoked() {
|
||||
String invalidId = "invalid";
|
||||
String createSessionId = this.createSession.getId();
|
||||
when(this.sessions.findById(any())).thenReturn(Mono.empty());
|
||||
when(this.resolver.resolveSessionIds(exchange)).thenReturn(Arrays.asList(invalidId));
|
||||
given(this.sessions.findById(any())).willReturn(Mono.empty());
|
||||
given(this.resolver.resolveSessionIds(this.exchange))
|
||||
.willReturn(Collections.singletonList(invalidId));
|
||||
|
||||
WebSession webSession = this.manager.getSession(exchange).block();
|
||||
WebSession webSession = this.manager.getSession(this.exchange).block();
|
||||
|
||||
assertThat(webSession.getId()).isEqualTo(createSessionId);
|
||||
verify(this.sessions).findById(invalidId);
|
||||
|
||||
Mono<String> mono = Mono.just("toTest");
|
||||
StepVerifier
|
||||
.create(mono)
|
||||
.expectNoEvent(Duration.ZERO);
|
||||
StepVerifier.create(mono).expectNoEvent(Duration.ZERO);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSessionWhenValidIdThenFoundSessionUsed() {
|
||||
String findByIdSessionId = this.findByIdSession.getId();
|
||||
when(this.sessions.findById(findByIdSessionId)).thenReturn(Mono.just(findByIdSession));
|
||||
when(this.resolver.resolveSessionIds(exchange)).thenReturn(Arrays.asList(findByIdSessionId));
|
||||
given(this.sessions.findById(findByIdSessionId))
|
||||
.willReturn(Mono.just(this.findByIdSession));
|
||||
given(this.resolver.resolveSessionIds(this.exchange))
|
||||
.willReturn(Arrays.asList(findByIdSessionId));
|
||||
|
||||
WebSession webSession = this.manager.getSession(exchange).block();
|
||||
WebSession webSession = this.manager.getSession(this.exchange).block();
|
||||
|
||||
assertThat(webSession.getId()).isEqualTo(findByIdSessionId);
|
||||
verify(this.sessions).findById(findByIdSessionId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,51 +16,59 @@
|
||||
|
||||
package org.springframework.session.web.server.session;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.session.ReactorSessionRepository;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.web.server.WebSession;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Tests for {@link SpringSessionWebSessionStore}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class SpringSessionWebSessionStoreTests<S extends Session> {
|
||||
|
||||
@Mock
|
||||
ReactorSessionRepository<S> sessionRepository;
|
||||
private ReactorSessionRepository<S> sessionRepository;
|
||||
|
||||
@Mock
|
||||
S createSession;
|
||||
private S createSession;
|
||||
|
||||
@Mock
|
||||
S findByIdSession;
|
||||
SpringSessionWebSessionStore<S> webSessionStore;
|
||||
private S findByIdSession;
|
||||
|
||||
private SpringSessionWebSessionStore<S> webSessionStore;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.webSessionStore = new SpringSessionWebSessionStore<>(sessionRepository);
|
||||
when(this.sessionRepository.findById(any())).thenReturn(Mono.just(findByIdSession));
|
||||
when(this.sessionRepository.createSession()).thenReturn(Mono.just(createSession));
|
||||
this.webSessionStore = new SpringSessionWebSessionStore<>(this.sessionRepository);
|
||||
given(this.sessionRepository.findById(any()))
|
||||
.willReturn(Mono.just(this.findByIdSession));
|
||||
given(this.sessionRepository.createSession())
|
||||
.willReturn(Mono.just(this.createSession));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorWhenNullRepositoryThenThrowsIllegalArgumentException() {
|
||||
new SpringSessionWebSessionStore<S>((ReactorSessionRepository<S>) null);
|
||||
new SpringSessionWebSessionStore<S>(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -72,7 +80,8 @@ public class SpringSessionWebSessionStoreTests<S extends Session> {
|
||||
|
||||
@Test
|
||||
public void createSessionWhenAddAttributeThenStarted() {
|
||||
when(createSession.getAttributeNames()).thenReturn(Collections.singleton("a"));
|
||||
given(this.createSession.getAttributeNames())
|
||||
.willReturn(Collections.singleton("a"));
|
||||
WebSession createdWebSession = this.webSessionStore.createSession().block();
|
||||
|
||||
assertThat(createdWebSession.isStarted()).isTrue();
|
||||
@@ -86,7 +95,8 @@ public class SpringSessionWebSessionStoreTests<S extends Session> {
|
||||
|
||||
assertThat(attributes.size()).isEqualTo(0);
|
||||
|
||||
when(this.createSession.getAttributeNames()).thenReturn(Collections.singleton("a"));
|
||||
given(this.createSession.getAttributeNames())
|
||||
.willReturn(Collections.singleton("a"));
|
||||
|
||||
assertThat(attributes.size()).isEqualTo(1);
|
||||
}
|
||||
@@ -99,7 +109,8 @@ public class SpringSessionWebSessionStoreTests<S extends Session> {
|
||||
|
||||
assertThat(attributes.isEmpty()).isTrue();
|
||||
|
||||
when(this.createSession.getAttributeNames()).thenReturn(Collections.singleton("a"));
|
||||
given(this.createSession.getAttributeNames())
|
||||
.willReturn(Collections.singleton("a"));
|
||||
|
||||
assertThat(attributes.isEmpty()).isFalse();
|
||||
}
|
||||
@@ -124,7 +135,8 @@ public class SpringSessionWebSessionStoreTests<S extends Session> {
|
||||
|
||||
@Test
|
||||
public void createSessionWhenGetAttributesAndContainsKeyAndFoundThenTrue() {
|
||||
when(this.createSession.getAttributeNames()).thenReturn(Collections.singleton("a"));
|
||||
given(this.createSession.getAttributeNames())
|
||||
.willReturn(Collections.singleton("a"));
|
||||
WebSession createdWebSession = this.webSessionStore.createSession().block();
|
||||
|
||||
Map<String, Object> attributes = createdWebSession.getAttributes();
|
||||
@@ -139,7 +151,7 @@ public class SpringSessionWebSessionStoreTests<S extends Session> {
|
||||
Map<String, Object> attributes = createdWebSession.getAttributes();
|
||||
attributes.put("a", "b");
|
||||
|
||||
verify(createSession).setAttribute("a", "b");
|
||||
verify(this.createSession).setAttribute("a", "b");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -149,7 +161,7 @@ public class SpringSessionWebSessionStoreTests<S extends Session> {
|
||||
Map<String, Object> attributes = createdWebSession.getAttributes();
|
||||
attributes.put("a", null);
|
||||
|
||||
verify(createSession).setAttribute("a", null);
|
||||
verify(this.createSession).setAttribute("a", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -159,7 +171,7 @@ public class SpringSessionWebSessionStoreTests<S extends Session> {
|
||||
Map<String, Object> attributes = createdWebSession.getAttributes();
|
||||
attributes.remove("a");
|
||||
|
||||
verify(createSession).removeAttribute("a");
|
||||
verify(this.createSession).removeAttribute("a");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -167,25 +179,27 @@ public class SpringSessionWebSessionStoreTests<S extends Session> {
|
||||
WebSession createdWebSession = this.webSessionStore.createSession().block();
|
||||
|
||||
Map<String, Object> attributes = createdWebSession.getAttributes();
|
||||
attributes.putAll(Collections.singletonMap("a","b"));
|
||||
attributes.putAll(Collections.singletonMap("a", "b"));
|
||||
|
||||
verify(createSession).setAttribute("a", "b");
|
||||
verify(this.createSession).setAttribute("a", "b");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createSessionWhenGetAttributesAndClearThenDelegatesToCreateSession() {
|
||||
when(this.createSession.getAttributeNames()).thenReturn(Collections.singleton("a"));
|
||||
given(this.createSession.getAttributeNames())
|
||||
.willReturn(Collections.singleton("a"));
|
||||
WebSession createdWebSession = this.webSessionStore.createSession().block();
|
||||
|
||||
Map<String, Object> attributes = createdWebSession.getAttributes();
|
||||
attributes.clear();
|
||||
|
||||
verify(createSession).removeAttribute("a");
|
||||
verify(this.createSession).removeAttribute("a");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createSessionWhenGetAttributesAndKeySetThenDelegatesToCreateSession() {
|
||||
when(this.createSession.getAttributeNames()).thenReturn(Collections.singleton("a"));
|
||||
given(this.createSession.getAttributeNames())
|
||||
.willReturn(Collections.singleton("a"));
|
||||
WebSession createdWebSession = this.webSessionStore.createSession().block();
|
||||
|
||||
Map<String, Object> attributes = createdWebSession.getAttributes();
|
||||
@@ -195,8 +209,9 @@ public class SpringSessionWebSessionStoreTests<S extends Session> {
|
||||
|
||||
@Test
|
||||
public void createSessionWhenGetAttributesAndValuesThenDelegatesToCreateSession() {
|
||||
when(this.createSession.getAttributeNames()).thenReturn(Collections.singleton("a"));
|
||||
when(this.createSession.getAttribute("a")).thenReturn("b");
|
||||
given(this.createSession.getAttributeNames())
|
||||
.willReturn(Collections.singleton("a"));
|
||||
given(this.createSession.getAttribute("a")).willReturn("b");
|
||||
WebSession createdWebSession = this.webSessionStore.createSession().block();
|
||||
|
||||
Map<String, Object> attributes = createdWebSession.getAttributes();
|
||||
@@ -207,20 +222,22 @@ public class SpringSessionWebSessionStoreTests<S extends Session> {
|
||||
@Test
|
||||
public void createSessionWhenGetAttributesAndEntrySetThenDelegatesToCreateSession() {
|
||||
String attrName = "attrName";
|
||||
when(createSession.getAttributeNames()).thenReturn(Collections.singleton(attrName));
|
||||
given(this.createSession.getAttributeNames())
|
||||
.willReturn(Collections.singleton(attrName));
|
||||
String attrValue = "attrValue";
|
||||
when(createSession.getAttribute(attrName)).thenReturn(attrValue);
|
||||
given(this.createSession.getAttribute(attrName)).willReturn(attrValue);
|
||||
WebSession createdWebSession = this.webSessionStore.createSession().block();
|
||||
|
||||
Map<String, Object> attributes = createdWebSession.getAttributes();
|
||||
Set<Map.Entry<String, Object>> entries = attributes.entrySet();
|
||||
|
||||
assertThat(entries).containsExactly(new AbstractMap.SimpleEntry<String, Object>(attrName, attrValue));
|
||||
assertThat(entries)
|
||||
.containsExactly(new AbstractMap.SimpleEntry<>(attrName, attrValue));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void storeSessionWhenInvokedThenSessionSaved() {
|
||||
when(this.sessionRepository.save(this.createSession)).thenReturn(Mono.empty());
|
||||
given(this.sessionRepository.save(this.createSession)).willReturn(Mono.empty());
|
||||
WebSession createdSession = this.webSessionStore.createSession().block();
|
||||
|
||||
this.webSessionStore.storeSession(createdSession).block();
|
||||
@@ -239,10 +256,11 @@ public class SpringSessionWebSessionStoreTests<S extends Session> {
|
||||
@Test
|
||||
public void removeSessionWhenInvokedThenSessionSaved() {
|
||||
String sessionId = "session-id";
|
||||
when(this.sessionRepository.delete(sessionId)).thenReturn(Mono.empty());
|
||||
given(this.sessionRepository.delete(sessionId)).willReturn(Mono.empty());
|
||||
|
||||
this.webSessionStore.removeSession(sessionId).block();
|
||||
|
||||
verify(this.sessionRepository).delete(sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user