Skip to content

Commit 17005c5

Browse files
committed
Add simple Redis SessionRepository implementation
See: #1408
1 parent 5485907 commit 17005c5

File tree

3 files changed

+884
-0
lines changed

3 files changed

+884
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
/*
2+
* Copyright 2014-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.session.data.redis;
18+
19+
import java.time.Duration;
20+
import java.time.Instant;
21+
import java.time.temporal.ChronoUnit;
22+
import java.util.Collections;
23+
import java.util.UUID;
24+
25+
import org.junit.jupiter.api.Test;
26+
import org.junit.jupiter.api.extension.ExtendWith;
27+
28+
import org.springframework.beans.factory.annotation.Autowired;
29+
import org.springframework.context.annotation.Bean;
30+
import org.springframework.context.annotation.Configuration;
31+
import org.springframework.data.redis.connection.RedisConnectionFactory;
32+
import org.springframework.data.redis.core.RedisTemplate;
33+
import org.springframework.session.MapSession;
34+
import org.springframework.session.config.annotation.web.http.EnableSpringHttpSession;
35+
import org.springframework.session.data.redis.SimpleRedisOperationsSessionRepository.RedisSession;
36+
import org.springframework.test.context.ContextConfiguration;
37+
import org.springframework.test.context.junit.jupiter.SpringExtension;
38+
import org.springframework.test.context.web.WebAppConfiguration;
39+
40+
import static org.assertj.core.api.Assertions.assertThat;
41+
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
42+
43+
/**
44+
* Integration tests for {@link SimpleRedisOperationsSessionRepository}.
45+
*
46+
* @author Vedran Pavic
47+
*/
48+
@ExtendWith(SpringExtension.class)
49+
@ContextConfiguration
50+
@WebAppConfiguration
51+
class SimpleRedisOperationsSessionRepositoryITests extends AbstractRedisITests {
52+
53+
@Autowired
54+
private SimpleRedisOperationsSessionRepository sessionRepository;
55+
56+
@Test
57+
void save_NewSession_ShouldSaveSession() {
58+
RedisSession session = createAndSaveSession(Instant.now());
59+
assertThat(session.getMaxInactiveInterval()).isEqualTo(
60+
Duration.ofSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS));
61+
assertThat(session.getAttributeNames())
62+
.isEqualTo(Collections.singleton("attribute1"));
63+
assertThat(session.<String>getAttribute("attribute1")).isEqualTo("value1");
64+
}
65+
66+
@Test
67+
void save_LastAccessedTimeInPast_ShouldExpireSession() {
68+
assertThat(createAndSaveSession(Instant.EPOCH)).isNull();
69+
}
70+
71+
@Test
72+
void save_DeletedSession_ShouldThrowException() {
73+
RedisSession session = createAndSaveSession(Instant.now());
74+
this.sessionRepository.deleteById(session.getId());
75+
assertThatIllegalStateException()
76+
.isThrownBy(() -> this.sessionRepository.save(session))
77+
.withMessage("Session was invalidated");
78+
}
79+
80+
@Test
81+
void save_ConcurrentUpdates_ShouldSaveSession() {
82+
RedisSession copy1 = createAndSaveSession(Instant.now());
83+
String sessionId = copy1.getId();
84+
RedisSession copy2 = this.sessionRepository.findById(sessionId);
85+
Instant now = Instant.now().truncatedTo(ChronoUnit.MILLIS);
86+
updateSession(copy1, now.plusSeconds(1L), "attribute2", "value2");
87+
this.sessionRepository.save(copy1);
88+
updateSession(copy2, now.plusSeconds(2L), "attribute3", "value3");
89+
this.sessionRepository.save(copy2);
90+
RedisSession session = this.sessionRepository.findById(sessionId);
91+
assertThat(session.getLastAccessedTime()).isEqualTo(now.plusSeconds(2L));
92+
assertThat(session.getAttributeNames()).hasSize(3);
93+
assertThat(session.<String>getAttribute("attribute1")).isEqualTo("value1");
94+
assertThat(session.<String>getAttribute("attribute2")).isEqualTo("value2");
95+
assertThat(session.<String>getAttribute("attribute3")).isEqualTo("value3");
96+
}
97+
98+
@Test
99+
void save_ChangeSessionIdAndUpdateAttribute_ShouldChangeSessionId() {
100+
RedisSession session = createAndSaveSession(Instant.now());
101+
String originalSessionId = session.getId();
102+
updateSession(session, Instant.now(), "attribute1", "value2");
103+
String newSessionId = session.changeSessionId();
104+
this.sessionRepository.save(session);
105+
RedisSession loaded = this.sessionRepository.findById(newSessionId);
106+
assertThat(loaded).isNotNull();
107+
assertThat(loaded.getAttributeNames()).hasSize(1);
108+
assertThat(loaded.<String>getAttribute("attribute1")).isEqualTo("value2");
109+
assertThat(this.sessionRepository.findById(originalSessionId)).isNull();
110+
}
111+
112+
@Test
113+
void save_OnlyChangeSessionId_ShouldChangeSessionId() {
114+
RedisSession session = createAndSaveSession(Instant.now());
115+
String originalSessionId = session.getId();
116+
String newSessionId = session.changeSessionId();
117+
this.sessionRepository.save(session);
118+
assertThat(this.sessionRepository.findById(newSessionId)).isNotNull();
119+
assertThat(this.sessionRepository.findById(originalSessionId)).isNull();
120+
}
121+
122+
@Test
123+
void save_ChangeSessionIdTwice_ShouldChangeSessionId() {
124+
RedisSession session = createAndSaveSession(Instant.now());
125+
String originalSessionId = session.getId();
126+
updateSession(session, Instant.now(), "attribute1", "value2");
127+
String newSessionId1 = session.changeSessionId();
128+
updateSession(session, Instant.now(), "attribute1", "value3");
129+
String newSessionId2 = session.changeSessionId();
130+
this.sessionRepository.save(session);
131+
assertThat(this.sessionRepository.findById(newSessionId1)).isNull();
132+
assertThat(this.sessionRepository.findById(newSessionId2)).isNotNull();
133+
assertThat(this.sessionRepository.findById(originalSessionId)).isNull();
134+
}
135+
136+
@Test
137+
void save_ChangeSessionIdOnNewSession_ShouldChangeSessionId() {
138+
RedisSession session = this.sessionRepository.createSession();
139+
String originalSessionId = session.getId();
140+
updateSession(session, Instant.now(), "attribute1", "value1");
141+
String newSessionId = session.changeSessionId();
142+
this.sessionRepository.save(session);
143+
assertThat(this.sessionRepository.findById(newSessionId)).isNotNull();
144+
assertThat(this.sessionRepository.findById(originalSessionId)).isNull();
145+
}
146+
147+
@Test
148+
void save_ChangeSessionIdSaveTwice_ShouldChangeSessionId() {
149+
RedisSession session = createAndSaveSession(Instant.now());
150+
String originalSessionId;
151+
originalSessionId = session.getId();
152+
updateSession(session, Instant.now(), "attribute1", "value1");
153+
String newSessionId = session.changeSessionId();
154+
this.sessionRepository.save(session);
155+
this.sessionRepository.save(session);
156+
assertThat(this.sessionRepository.findById(newSessionId)).isNotNull();
157+
assertThat(this.sessionRepository.findById(originalSessionId)).isNull();
158+
}
159+
160+
@Test
161+
void save_ChangeSessionIdOnDeletedSession_ShouldThrowException() {
162+
RedisSession session = createAndSaveSession(Instant.now());
163+
String originalSessionId = session.getId();
164+
this.sessionRepository.deleteById(originalSessionId);
165+
updateSession(session, Instant.now(), "attribute1", "value1");
166+
String newSessionId = session.changeSessionId();
167+
assertThatIllegalStateException()
168+
.isThrownBy(() -> this.sessionRepository.save(session))
169+
.withMessage("Session was invalidated");
170+
assertThat(this.sessionRepository.findById(newSessionId)).isNull();
171+
assertThat(this.sessionRepository.findById(originalSessionId)).isNull();
172+
}
173+
174+
@Test
175+
void save_ChangeSessionIdConcurrent_ShouldThrowException() {
176+
RedisSession copy1 = createAndSaveSession(Instant.now());
177+
String originalSessionId = copy1.getId();
178+
RedisSession copy2 = this.sessionRepository.findById(originalSessionId);
179+
Instant now = Instant.now().truncatedTo(ChronoUnit.MILLIS);
180+
updateSession(copy1, now.plusSeconds(1L), "attribute2", "value2");
181+
String newSessionId1 = copy1.changeSessionId();
182+
this.sessionRepository.save(copy1);
183+
updateSession(copy2, now.plusSeconds(2L), "attribute3", "value3");
184+
String newSessionId2 = copy2.changeSessionId();
185+
assertThatIllegalStateException()
186+
.isThrownBy(() -> this.sessionRepository.save(copy2))
187+
.withMessage("Session was invalidated");
188+
assertThat(this.sessionRepository.findById(newSessionId1)).isNotNull();
189+
assertThat(this.sessionRepository.findById(newSessionId2)).isNull();
190+
assertThat(this.sessionRepository.findById(originalSessionId)).isNull();
191+
}
192+
193+
@Test
194+
void deleteById_ValidSession_ShouldDeleteSession() {
195+
RedisSession session = createAndSaveSession(Instant.now());
196+
this.sessionRepository.deleteById(session.getId());
197+
assertThat(this.sessionRepository.findById(session.getId())).isNull();
198+
}
199+
200+
@Test
201+
void deleteById_DeletedSession_ShouldDoNothing() {
202+
RedisSession session = createAndSaveSession(Instant.now());
203+
this.sessionRepository.deleteById(session.getId());
204+
this.sessionRepository.deleteById(session.getId());
205+
assertThat(this.sessionRepository.findById(session.getId())).isNull();
206+
}
207+
208+
@Test
209+
void deleteById_NonexistentSession_ShouldDoNothing() {
210+
String sessionId = UUID.randomUUID().toString();
211+
this.sessionRepository.deleteById(sessionId);
212+
assertThat(this.sessionRepository.findById(sessionId)).isNull();
213+
}
214+
215+
private RedisSession createAndSaveSession(Instant lastAccessedTime) {
216+
RedisSession session = this.sessionRepository.createSession();
217+
session.setLastAccessedTime(lastAccessedTime);
218+
session.setAttribute("attribute1", "value1");
219+
this.sessionRepository.save(session);
220+
return this.sessionRepository.findById(session.getId());
221+
}
222+
223+
private static void updateSession(RedisSession session, Instant lastAccessedTime,
224+
String attributeName, Object attributeValue) {
225+
session.setLastAccessedTime(lastAccessedTime);
226+
session.setAttribute(attributeName, attributeValue);
227+
}
228+
229+
@Configuration
230+
@EnableSpringHttpSession
231+
static class Config extends BaseConfig {
232+
233+
@Bean
234+
public SimpleRedisOperationsSessionRepository sessionRepository(
235+
RedisConnectionFactory redisConnectionFactory) {
236+
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
237+
redisTemplate.setConnectionFactory(redisConnectionFactory);
238+
redisTemplate.afterPropertiesSet();
239+
return new SimpleRedisOperationsSessionRepository(redisTemplate);
240+
}
241+
242+
}
243+
244+
}

0 commit comments

Comments
 (0)