Align Spring Session MongoDB with WebSession API.
Introduce new state to MongoSession denoting if a session is new or not. Only perform a save on a non-new MongoSession if it already exists in the MongoDB. Otherwise, throw an IllegalStateException. Resolved #47.
This commit is contained in:
@@ -95,7 +95,19 @@ public class MongoOperationsSessionRepository
|
||||
|
||||
@Override
|
||||
public void save(MongoSession session) {
|
||||
this.mongoOperations.save(convertToDBObject(this.mongoSessionConverter, session), this.collectionName);
|
||||
|
||||
if (session.isNew()) {
|
||||
|
||||
session.setNew(false);
|
||||
this.mongoOperations.save(convertToDBObject(this.mongoSessionConverter, session), this.collectionName);
|
||||
} else {
|
||||
|
||||
if (findSession(session.getId()) == null) {
|
||||
throw new IllegalStateException("Session was invalidated");
|
||||
} else {
|
||||
this.mongoOperations.save(convertToDBObject(this.mongoSessionConverter, session), this.collectionName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -51,6 +51,7 @@ public class MongoSession implements Session {
|
||||
private long intervalSeconds;
|
||||
@Getter @Setter private Date expireAt;
|
||||
private Map<String, Object> attrs = new HashMap<>();
|
||||
private boolean isNew = true;
|
||||
|
||||
public MongoSession() {
|
||||
this(MongoOperationsSessionRepository.DEFAULT_INACTIVE_INTERVAL);
|
||||
@@ -129,6 +130,14 @@ public class MongoSession implements Session {
|
||||
return this.intervalSeconds >= 0 && new Date().after(this.expireAt);
|
||||
}
|
||||
|
||||
public void setNew(boolean isNew) {
|
||||
this.isNew = isNew;
|
||||
}
|
||||
|
||||
public boolean isNew() {
|
||||
return this.isNew;
|
||||
}
|
||||
|
||||
static String coverDot(String attributeName) {
|
||||
return attributeName.replace('.', DOT_COVER_CHAR);
|
||||
}
|
||||
|
||||
@@ -107,9 +107,18 @@ public class ReactiveMongoOperationsSessionRepository
|
||||
@Override
|
||||
public Mono<Void> save(MongoSession session) {
|
||||
|
||||
return this.mongoOperations
|
||||
.save(convertToDBObject(this.mongoSessionConverter, session), this.collectionName)
|
||||
.then();
|
||||
if (session.isNew()) {
|
||||
|
||||
session.setNew(false);
|
||||
return this.mongoOperations.save(convertToDBObject(this.mongoSessionConverter, session), this.collectionName)
|
||||
.then();
|
||||
} else {
|
||||
|
||||
return findSession(session.getId())
|
||||
.map(document -> this.mongoOperations.save(convertToDBObject(this.mongoSessionConverter, session), this.collectionName))
|
||||
.switchIfEmpty(Mono.error(new IllegalStateException("Session was invalidated")))
|
||||
.then();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -62,36 +62,42 @@ public class MongoOperationsSessionRepositoryTest {
|
||||
private MongoOperationsSessionRepository repository;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
public void setUp() {
|
||||
|
||||
this.repository = new MongoOperationsSessionRepository(this.mongoOperations);
|
||||
this.repository.setMongoSessionConverter(this.converter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateSession() throws Exception {
|
||||
public void shouldCreateSession() {
|
||||
|
||||
// when
|
||||
MongoSession session = this.repository.createSession();
|
||||
|
||||
// then
|
||||
assertThat(session.getId()).isNotEmpty();
|
||||
assertThat(session.isNew()).isTrue();
|
||||
assertThat(session.getMaxInactiveInterval().getSeconds())
|
||||
.isEqualTo(MongoOperationsSessionRepository.DEFAULT_INACTIVE_INTERVAL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateSessionWhenMaxInactiveIntervalNotDefined() throws Exception {
|
||||
public void shouldCreateSessionWhenMaxInactiveIntervalNotDefined() {
|
||||
|
||||
// when
|
||||
this.repository.setMaxInactiveIntervalInSeconds(null);
|
||||
MongoSession session = this.repository.createSession();
|
||||
|
||||
// then
|
||||
assertThat(session.getId()).isNotEmpty();
|
||||
assertThat(session.isNew()).isTrue();
|
||||
assertThat(session.getMaxInactiveInterval().getSeconds())
|
||||
.isEqualTo(MongoOperationsSessionRepository.DEFAULT_INACTIVE_INTERVAL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSaveSession() throws Exception {
|
||||
public void shouldSaveNewSession() {
|
||||
|
||||
// given
|
||||
MongoSession session = new MongoSession();
|
||||
BasicDBObject dbSession = new BasicDBObject();
|
||||
@@ -99,6 +105,44 @@ public class MongoOperationsSessionRepositoryTest {
|
||||
given(this.converter.convert(session,
|
||||
TypeDescriptor.valueOf(MongoSession.class),
|
||||
TypeDescriptor.valueOf(DBObject.class))).willReturn(dbSession);
|
||||
|
||||
// when
|
||||
this.repository.save(session);
|
||||
|
||||
// then
|
||||
verify(this.mongoOperations).save(dbSession, MongoOperationsSessionRepository.DEFAULT_COLLECTION_NAME);
|
||||
|
||||
assertThat(session.isNew()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldHandleInvalidatedSession() {
|
||||
|
||||
MongoSession session = new MongoSession();
|
||||
session.setNew(false);
|
||||
|
||||
assertThatIllegalStateException().isThrownBy(() -> {
|
||||
this.repository.save(session);
|
||||
}).withMessage("Session was invalidated");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSaveExistingSession() {
|
||||
|
||||
// given
|
||||
MongoSession session = new MongoSession();
|
||||
session.setNew(false);
|
||||
BasicDBObject dbSession = new BasicDBObject();
|
||||
|
||||
Document sessionDocument = new Document();
|
||||
|
||||
given(this.mongoOperations.findById(session.getId(), Document.class,
|
||||
MongoOperationsSessionRepository.DEFAULT_COLLECTION_NAME)).willReturn(sessionDocument);
|
||||
|
||||
given(this.converter.convert(session,
|
||||
TypeDescriptor.valueOf(MongoSession.class),
|
||||
TypeDescriptor.valueOf(DBObject.class))).willReturn(dbSession);
|
||||
|
||||
// when
|
||||
this.repository.save(session);
|
||||
|
||||
@@ -107,7 +151,8 @@ public class MongoOperationsSessionRepositoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetSession() throws Exception {
|
||||
public void shouldGetSession() {
|
||||
|
||||
// given
|
||||
String sessionId = UUID.randomUUID().toString();
|
||||
Document sessionDocument = new Document();
|
||||
@@ -128,7 +173,8 @@ public class MongoOperationsSessionRepositoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldHandleExpiredSession() throws Exception {
|
||||
public void shouldHandleExpiredSession() {
|
||||
|
||||
// given
|
||||
String sessionId = UUID.randomUUID().toString();
|
||||
Document sessionDocument = new Document();
|
||||
@@ -152,7 +198,8 @@ public class MongoOperationsSessionRepositoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDeleteSession() throws Exception {
|
||||
public void shouldDeleteSession() {
|
||||
|
||||
// given
|
||||
String sessionId = UUID.randomUUID().toString();
|
||||
|
||||
@@ -175,7 +222,8 @@ public class MongoOperationsSessionRepositoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetSessionsMapByPrincipal() throws Exception {
|
||||
public void shouldGetSessionsMapByPrincipal() {
|
||||
|
||||
// given
|
||||
String principalNameIndexName = FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME;
|
||||
|
||||
@@ -203,7 +251,8 @@ public class MongoOperationsSessionRepositoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnEmptyMapForNotSupportedIndex() throws Exception {
|
||||
public void shouldReturnEmptyMapForNotSupportedIndex() {
|
||||
|
||||
// given
|
||||
String index = "some_not_supported_index_name";
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import static org.mockito.BDDMockito.*;
|
||||
import static org.mockito.BDDMockito.mock;
|
||||
import static org.mockito.BDDMockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.springframework.session.data.mongo.ReactiveMongoOperationsSessionRepository.DEFAULT_COLLECTION_NAME;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -84,6 +85,7 @@ public class ReactiveMongoOperationsSessionRepositoryTest {
|
||||
.as(StepVerifier::create)
|
||||
.expectNextMatches(mongoSession -> {
|
||||
assertThat(mongoSession.getId()).isNotEmpty();
|
||||
assertThat(mongoSession.isNew()).isTrue();
|
||||
assertThat(mongoSession.getMaxInactiveInterval().getSeconds())
|
||||
.isEqualTo(ReactiveMongoOperationsSessionRepository.DEFAULT_INACTIVE_INTERVAL);
|
||||
return true;
|
||||
@@ -102,6 +104,7 @@ public class ReactiveMongoOperationsSessionRepositoryTest {
|
||||
.as(StepVerifier::create)
|
||||
.expectNextMatches(mongoSession -> {
|
||||
assertThat(mongoSession.getId()).isNotEmpty();
|
||||
assertThat(mongoSession.isNew()).isTrue();
|
||||
assertThat(mongoSession.getMaxInactiveInterval().getSeconds())
|
||||
.isEqualTo(ReactiveMongoOperationsSessionRepository.DEFAULT_INACTIVE_INTERVAL);
|
||||
return true;
|
||||
@@ -114,8 +117,12 @@ public class ReactiveMongoOperationsSessionRepositoryTest {
|
||||
|
||||
// given
|
||||
MongoSession session = new MongoSession();
|
||||
Document sessionDocument = new Document();
|
||||
BasicDBObject dbSession = new BasicDBObject();
|
||||
|
||||
given(this.mongoOperations.findById(session.getId(), Document.class,
|
||||
DEFAULT_COLLECTION_NAME)).willReturn(Mono.just(sessionDocument));
|
||||
|
||||
given(this.converter.convert(session,
|
||||
TypeDescriptor.valueOf(MongoSession.class),
|
||||
TypeDescriptor.valueOf(DBObject.class))).willReturn(dbSession);
|
||||
@@ -127,7 +134,30 @@ public class ReactiveMongoOperationsSessionRepositoryTest {
|
||||
.as(StepVerifier::create)
|
||||
.verifyComplete();
|
||||
|
||||
verify(this.mongoOperations).save(dbSession, ReactiveMongoOperationsSessionRepository.DEFAULT_COLLECTION_NAME);
|
||||
assertThat(session.isNew()).isFalse();
|
||||
verify(this.mongoOperations).save(dbSession, DEFAULT_COLLECTION_NAME);
|
||||
verifyNoMoreInteractions(this.mongoOperations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateAnErrorWhenSavingSessionNotInMongo() {
|
||||
|
||||
// given
|
||||
MongoSession session = new MongoSession();
|
||||
session.setNew(false);
|
||||
|
||||
given(this.mongoOperations.findById(session.getId(), Document.class,
|
||||
DEFAULT_COLLECTION_NAME)).willReturn(Mono.empty());
|
||||
|
||||
// when
|
||||
this.repository.save(session)
|
||||
.as(StepVerifier::create)
|
||||
.verifyErrorMessage("Session was invalidated");
|
||||
|
||||
assertThat(session.isNew()).isFalse();
|
||||
|
||||
verify(this.mongoOperations).findById(session.getId(), Document.class, DEFAULT_COLLECTION_NAME);
|
||||
verifyNoMoreInteractions(this.mongoOperations);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -138,7 +168,7 @@ public class ReactiveMongoOperationsSessionRepositoryTest {
|
||||
Document sessionDocument = new Document();
|
||||
|
||||
given(this.mongoOperations.findById(sessionId, Document.class,
|
||||
ReactiveMongoOperationsSessionRepository.DEFAULT_COLLECTION_NAME)).willReturn(Mono.just(sessionDocument));
|
||||
DEFAULT_COLLECTION_NAME)).willReturn(Mono.just(sessionDocument));
|
||||
|
||||
MongoSession session = new MongoSession();
|
||||
|
||||
@@ -160,9 +190,9 @@ public class ReactiveMongoOperationsSessionRepositoryTest {
|
||||
Document sessionDocument = new Document();
|
||||
|
||||
given(this.mongoOperations.findById(sessionId, Document.class,
|
||||
ReactiveMongoOperationsSessionRepository.DEFAULT_COLLECTION_NAME)).willReturn(Mono.just(sessionDocument));
|
||||
DEFAULT_COLLECTION_NAME)).willReturn(Mono.just(sessionDocument));
|
||||
|
||||
given(this.mongoOperations.remove(sessionDocument, ReactiveMongoOperationsSessionRepository.DEFAULT_COLLECTION_NAME))
|
||||
given(this.mongoOperations.remove(sessionDocument, DEFAULT_COLLECTION_NAME))
|
||||
.willReturn(Mono.just(DeleteResult.acknowledged(1)));
|
||||
|
||||
MongoSession session = mock(MongoSession.class);
|
||||
@@ -177,8 +207,7 @@ public class ReactiveMongoOperationsSessionRepositoryTest {
|
||||
.verifyComplete();
|
||||
|
||||
// then
|
||||
verify(this.mongoOperations).remove(any(Document.class),
|
||||
eq(ReactiveMongoOperationsSessionRepository.DEFAULT_COLLECTION_NAME));
|
||||
verify(this.mongoOperations).remove(any(Document.class), eq(DEFAULT_COLLECTION_NAME));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -189,7 +218,7 @@ public class ReactiveMongoOperationsSessionRepositoryTest {
|
||||
Document sessionDocument = new Document();
|
||||
|
||||
given(this.mongoOperations.findById(sessionId, Document.class,
|
||||
ReactiveMongoOperationsSessionRepository.DEFAULT_COLLECTION_NAME)).willReturn(Mono.just(sessionDocument));
|
||||
DEFAULT_COLLECTION_NAME)).willReturn(Mono.just(sessionDocument));
|
||||
|
||||
given(this.mongoOperations.remove(sessionDocument, "sessions"))
|
||||
.willReturn(Mono.just(DeleteResult.acknowledged(1)));
|
||||
@@ -204,9 +233,7 @@ public class ReactiveMongoOperationsSessionRepositoryTest {
|
||||
.as(StepVerifier::create)
|
||||
.verifyComplete();
|
||||
|
||||
verify(this.mongoOperations).remove(any(Document.class),
|
||||
eq(ReactiveMongoOperationsSessionRepository.DEFAULT_COLLECTION_NAME));
|
||||
|
||||
verify(this.mongoOperations).remove(any(Document.class), eq(DEFAULT_COLLECTION_NAME));
|
||||
verify(this.eventPublisher).publishEvent(any(SessionDeletedEvent.class));
|
||||
}
|
||||
|
||||
@@ -225,5 +252,8 @@ public class ReactiveMongoOperationsSessionRepositoryTest {
|
||||
// then
|
||||
verify(this.blockingMongoOperations, times(1)).indexOps((String) any());
|
||||
verify(this.converter, times(1)).ensureIndexes(indexOperations);
|
||||
|
||||
verifyNoMoreInteractions(this.blockingMongoOperations);
|
||||
verifyNoMoreInteractions(this.converter);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user