Bael 4779 (#13465)
* first commit for Spring Data Redis TTL * BAEL-4779: Removed incorrect module * removed mvn wrapper * Reduced wait time to check expiration * J17 -> J11 * spring boot redis added to JDK 9 and above profile * pulled latest from master * restored from master * resolved from master * Update pom.xml * Update pom.xml * using Collections api available in J15 * updated Integration test class name --------- Co-authored-by: s9m33r <no-reply> Co-authored-by: Loredana Crusoveanu <lore.crusoveanu@gmail.com>
This commit is contained in:
parent
f93f1d2c1e
commit
350a3c3575
6
pom.xml
6
pom.xml
|
@ -999,7 +999,7 @@
|
||||||
<module>spring-5-webflux-2</module>
|
<module>spring-5-webflux-2</module>
|
||||||
<module>spring-activiti</module>
|
<module>spring-activiti</module>
|
||||||
<module>spring-batch-2</module>
|
<module>spring-batch-2</module>
|
||||||
<module>spring-boot-modules/spring-caching-2</module>
|
<module>spring-boot-modules/spring-caching-2</module>
|
||||||
<module>spring-core-2</module>
|
<module>spring-core-2</module>
|
||||||
<module>spring-core-3</module>
|
<module>spring-core-3</module>
|
||||||
<module>spring-core-5</module>
|
<module>spring-core-5</module>
|
||||||
|
@ -1022,6 +1022,7 @@
|
||||||
<module>webrtc</module>
|
<module>webrtc</module>
|
||||||
<module>persistence-modules/java-mongodb</module>
|
<module>persistence-modules/java-mongodb</module>
|
||||||
<module>messaging-modules/spring-apache-camel</module>
|
<module>messaging-modules/spring-apache-camel</module>
|
||||||
|
<module>spring-boot-modules/spring-boot-redis</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
@ -1258,7 +1259,7 @@
|
||||||
<module>spring-5-webflux-2</module>
|
<module>spring-5-webflux-2</module>
|
||||||
<module>spring-activiti</module>
|
<module>spring-activiti</module>
|
||||||
<module>spring-batch-2</module>
|
<module>spring-batch-2</module>
|
||||||
<module>spring-boot-modules/spring-caching-2</module>
|
<module>spring-boot-modules/spring-caching-2</module>
|
||||||
<module>spring-core-2</module>
|
<module>spring-core-2</module>
|
||||||
<module>spring-core-3</module>
|
<module>spring-core-3</module>
|
||||||
<module>spring-core-5</module>
|
<module>spring-core-5</module>
|
||||||
|
@ -1281,6 +1282,7 @@
|
||||||
<module>persistence-modules/java-mongodb</module>
|
<module>persistence-modules/java-mongodb</module>
|
||||||
<module>libraries-2</module>
|
<module>libraries-2</module>
|
||||||
<module>messaging-modules/spring-apache-camel</module>
|
<module>messaging-modules/spring-apache-camel</module>
|
||||||
|
<module>spring-boot-modules/spring-boot-redis</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
|
|
@ -106,4 +106,4 @@
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
HELP.md
|
||||||
|
target/
|
||||||
|
.mvn
|
||||||
|
mvnw
|
||||||
|
mvnw.cmd
|
||||||
|
!**/src/main/**/target/
|
||||||
|
!**/src/test/**/target/
|
||||||
|
|
||||||
|
### STS ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
|
@ -0,0 +1,69 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>3.0.2</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
<groupId>com.baelding</groupId>
|
||||||
|
<artifactId>spring-boot-redis</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<name>spring-boot-redis</name>
|
||||||
|
<description>Demo project for Spring Boot with Spring Data Redis</description>
|
||||||
|
<properties>
|
||||||
|
<java.version>15</java.version>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>it.ozimov</groupId>
|
||||||
|
<artifactId>embedded-redis</artifactId>
|
||||||
|
<version>0.7.3</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-webflux</artifactId>
|
||||||
|
<version>6.0.3</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<excludes>
|
||||||
|
<exclude>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
</exclude>
|
||||||
|
</excludes>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.baelding.springbootredis;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class SpringBootRedisApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(SpringBootRedisApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package com.baelding.springbootredis.config;
|
||||||
|
|
||||||
|
import com.baelding.springbootredis.model.Session;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.ApplicationListener;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||||
|
import org.springframework.data.redis.core.RedisKeyExpiredEvent;
|
||||||
|
import org.springframework.data.redis.core.RedisKeyValueAdapter;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.data.redis.core.convert.KeyspaceConfiguration;
|
||||||
|
import org.springframework.data.redis.core.convert.MappingConfiguration;
|
||||||
|
import org.springframework.data.redis.core.index.IndexConfiguration;
|
||||||
|
import org.springframework.data.redis.core.mapping.RedisMappingContext;
|
||||||
|
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableRedisRepositories(enableKeyspaceEvents = RedisKeyValueAdapter.EnableKeyspaceEvents.ON_STARTUP)
|
||||||
|
@Slf4j
|
||||||
|
public class RedisConfiguration {
|
||||||
|
@Bean
|
||||||
|
public RedisTemplate<String, Session> getRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
|
||||||
|
RedisTemplate<String, Session> redisTemplate = new RedisTemplate<>();
|
||||||
|
redisTemplate.setConnectionFactory(redisConnectionFactory);
|
||||||
|
|
||||||
|
return redisTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RedisMappingContext keyValueMappingContext() {
|
||||||
|
return new RedisMappingContext(new MappingConfiguration(new IndexConfiguration(), new MyKeyspaceConfiguration()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MyKeyspaceConfiguration extends KeyspaceConfiguration {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Iterable<KeyspaceSettings> initialConfiguration() {
|
||||||
|
KeyspaceSettings keyspaceSettings = new KeyspaceSettings(Session.class, "session");
|
||||||
|
keyspaceSettings.setTimeToLive(60L);
|
||||||
|
return Collections.singleton(keyspaceSettings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public static class SessionExpiredEventListener {
|
||||||
|
@EventListener
|
||||||
|
public void handleRedisKeyExpiredEvent(RedisKeyExpiredEvent<Session> event) {
|
||||||
|
Session expiredSession = (Session) event.getValue();
|
||||||
|
assert expiredSession != null;
|
||||||
|
log.info("Session with key={} has expired", expiredSession.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
package com.baelding.springbootredis.controller;
|
||||||
|
|
||||||
|
import com.baelding.springbootredis.dto.SessionCreateRequest;
|
||||||
|
import com.baelding.springbootredis.model.Session;
|
||||||
|
import com.baelding.springbootredis.service.cache.session.SessionCache;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/v1/sessions")
|
||||||
|
public class SessionController {
|
||||||
|
private static final String LOCATION_HEADER_VALUE_FORMAT = "/v1/sessions/%s";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SessionCache sessionCache;
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public List<Session> getAllSessions() {
|
||||||
|
return sessionCache.getAllSessions();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public Session getSession(@PathVariable("id") String id) {
|
||||||
|
return sessionCache.getSession(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
public ResponseEntity<Session> createASession(@RequestBody SessionCreateRequest sessionCreateRequest) {
|
||||||
|
Session createdSession = sessionCache.createASession(Session.builder().expirationInSeconds(sessionCreateRequest.getExpirationInSeconds()).build());
|
||||||
|
|
||||||
|
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
|
||||||
|
headers.set(HttpHeaders.LOCATION, String.format(LOCATION_HEADER_VALUE_FORMAT, createdSession.getId()));
|
||||||
|
|
||||||
|
return new ResponseEntity<>(createdSession, new HttpHeaders(headers), HttpStatus.CREATED);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package com.baelding.springbootredis.dto;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class SessionCreateRequest {
|
||||||
|
private Long expirationInSeconds;
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.baelding.springbootredis.exception.session;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
|
||||||
|
@ResponseStatus(value = HttpStatus.NOT_FOUND)
|
||||||
|
public class SessionNotFoundException extends RuntimeException {
|
||||||
|
private static final String MESSAGE_FORMAT = "Session with id=%s doesn't exists!";
|
||||||
|
public SessionNotFoundException(String id) {
|
||||||
|
super(String.format(MESSAGE_FORMAT, id));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.baelding.springbootredis.model;
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
|
import org.springframework.data.redis.core.RedisHash;
|
||||||
|
import org.springframework.data.redis.core.TimeToLive;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@RedisHash(timeToLive = 60L)
|
||||||
|
public class Session {
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
@TimeToLive
|
||||||
|
private Long expirationInSeconds;
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.baelding.springbootredis.repository;
|
||||||
|
|
||||||
|
import com.baelding.springbootredis.model.Session;
|
||||||
|
import org.springframework.data.repository.CrudRepository;
|
||||||
|
|
||||||
|
public interface SessionRepository extends CrudRepository<Session, String> {
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package com.baelding.springbootredis.service.cache.session;
|
||||||
|
|
||||||
|
import com.baelding.springbootredis.exception.session.SessionNotFoundException;
|
||||||
|
import com.baelding.springbootredis.model.Session;
|
||||||
|
import com.baelding.springbootredis.repository.SessionRepository;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.UnaryOperator;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class RedisSessionCache implements SessionCache {
|
||||||
|
@Autowired
|
||||||
|
private SessionRepository sessionRepository;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Session createASession(Session session) {
|
||||||
|
return sessionRepository.save(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Session getSession(String id) {
|
||||||
|
return sessionRepository.findById(id).orElseThrow(() -> new SessionNotFoundException(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Session> getAllSessions() {
|
||||||
|
return Stream.iterate(sessionRepository.findAll().iterator(), Iterator::hasNext, UnaryOperator.identity()).map(Iterator::next).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.baelding.springbootredis.service.cache.session;
|
||||||
|
|
||||||
|
import com.baelding.springbootredis.model.Session;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface SessionCache {
|
||||||
|
Session createASession(Session session);
|
||||||
|
Session getSession(String id);
|
||||||
|
List<Session> getAllSessions();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -0,0 +1,146 @@
|
||||||
|
package com.baelding.springbootredis;
|
||||||
|
|
||||||
|
import com.baelding.springbootredis.config.RedisTestConfiguration;
|
||||||
|
import com.baelding.springbootredis.dto.SessionCreateRequest;
|
||||||
|
import com.baelding.springbootredis.model.Session;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = RedisTestConfiguration.class)
|
||||||
|
class SpringBootRedisApplicationIntegrationTest {
|
||||||
|
|
||||||
|
private static final String V1_SESSIONS_ENDPOINT = "/v1/sessions";
|
||||||
|
private static final String V1_GET_SESSION_BY_ID_ENDPOINT_TEMPLATE = V1_SESSIONS_ENDPOINT + "/%s";
|
||||||
|
@Autowired
|
||||||
|
private WebTestClient webTestClient;
|
||||||
|
private static Random random;
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
public static void beforeAll() {
|
||||||
|
random = new Random();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("""
|
||||||
|
WHEN get session endpoint is called
|
||||||
|
THEN return a success response.
|
||||||
|
""")
|
||||||
|
void shouldBeAbleToCallGetSessionsEndpoint() {
|
||||||
|
webTestClient.get().uri(V1_SESSIONS_ENDPOINT).exchange().expectStatus().isOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("""
|
||||||
|
WHEN requested to create a session with certain expiration value
|
||||||
|
THEN successfully create a session with the desired expiration.
|
||||||
|
""")
|
||||||
|
void shouldBeAbleToCreateASessionWithCertainExpiration() {
|
||||||
|
Long expirationInSeconds = 10L;
|
||||||
|
|
||||||
|
SessionCreateRequest sessionCreateRequest = SessionCreateRequest.builder().expirationInSeconds(expirationInSeconds).build();
|
||||||
|
|
||||||
|
Session session = webTestClient.post().uri(V1_SESSIONS_ENDPOINT).bodyValue(sessionCreateRequest).exchange().expectStatus().isCreated().expectHeader().exists(HttpHeaders.LOCATION).expectBody(Session.class).returnResult().getResponseBody();
|
||||||
|
|
||||||
|
Assertions.assertNotNull(session);
|
||||||
|
Assertions.assertEquals(expirationInSeconds, session.getExpirationInSeconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("""
|
||||||
|
GIVEN one or multiple session exists
|
||||||
|
WHEN get sessions endpoint is called
|
||||||
|
THEN return the all the existing session.
|
||||||
|
""")
|
||||||
|
void shouldBeAbleToGetTheExistingSessions() {
|
||||||
|
// Given
|
||||||
|
SessionCreateRequest session = SessionCreateRequest.builder().expirationInSeconds(300L).build();
|
||||||
|
|
||||||
|
int numberOfSessionsToCreate = random.nextInt(5);
|
||||||
|
|
||||||
|
List<Session> createdSessions = IntStream.range(0, numberOfSessionsToCreate)
|
||||||
|
.mapToObj(i -> webTestClient.post().uri(V1_SESSIONS_ENDPOINT).bodyValue(session).exchange().expectStatus().isCreated().expectBody(Session.class).returnResult().getResponseBody())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// WHEN
|
||||||
|
webTestClient.get().uri(V1_SESSIONS_ENDPOINT).exchange().expectStatus()
|
||||||
|
// THEN
|
||||||
|
.isOk().expectBodyList(Session.class).value(sessions -> createdSessions.forEach(createdSession -> Assertions.assertTrue(sessions.contains(createdSession))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("""
|
||||||
|
GIVEN a session is created with a given identifier
|
||||||
|
WHEN the session with the identifier is requested
|
||||||
|
THEN return the session
|
||||||
|
""")
|
||||||
|
void getSessionById() {
|
||||||
|
// GIVEN
|
||||||
|
SessionCreateRequest sessionCreateRequest = SessionCreateRequest.builder().expirationInSeconds(10L).build();
|
||||||
|
|
||||||
|
Session createdSession = webTestClient.post().uri(V1_SESSIONS_ENDPOINT).bodyValue(sessionCreateRequest).exchange().expectStatus().isCreated().expectBody(Session.class).returnResult().getResponseBody();
|
||||||
|
Assertions.assertNotNull(createdSession);
|
||||||
|
|
||||||
|
// WHEN
|
||||||
|
webTestClient.get().uri(String.format(V1_GET_SESSION_BY_ID_ENDPOINT_TEMPLATE, createdSession.getId())).exchange()
|
||||||
|
// THEN
|
||||||
|
.expectStatus().isOk().expectBody(Session.class).isEqualTo(createdSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("""
|
||||||
|
GIVEN a session identifier which doesn't exists
|
||||||
|
WHEN the session with the identifier is requested
|
||||||
|
THEN return 404 not found
|
||||||
|
""")
|
||||||
|
void getSessionByIdNotFound() {
|
||||||
|
// GIVEN
|
||||||
|
String sessionId = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
// WHEN
|
||||||
|
webTestClient.get().uri(String.format(V1_GET_SESSION_BY_ID_ENDPOINT_TEMPLATE, sessionId)).exchange()
|
||||||
|
// THEN
|
||||||
|
.expectStatus().isNotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("""
|
||||||
|
GIVEN a session is created with a stipulated expiration
|
||||||
|
WHEN the session is requested before the expiration period
|
||||||
|
THEN return the session
|
||||||
|
|
||||||
|
WHEN the same session is requested after the expiration period
|
||||||
|
THEN return 404 not found
|
||||||
|
""")
|
||||||
|
void sessionExpiration() throws InterruptedException {
|
||||||
|
long expirationInSeconds = 3L;
|
||||||
|
|
||||||
|
// GIVEN
|
||||||
|
SessionCreateRequest sessionCreateRequest = SessionCreateRequest.builder().expirationInSeconds(expirationInSeconds).build();
|
||||||
|
|
||||||
|
Session createdSession = webTestClient.post().uri(V1_SESSIONS_ENDPOINT).bodyValue(sessionCreateRequest).exchange().expectStatus().isCreated().expectBody(Session.class).returnResult().getResponseBody();
|
||||||
|
Assertions.assertNotNull(createdSession);
|
||||||
|
|
||||||
|
// WHEN
|
||||||
|
webTestClient.get().uri(String.format(V1_GET_SESSION_BY_ID_ENDPOINT_TEMPLATE, createdSession.getId())).exchange()
|
||||||
|
// THEN
|
||||||
|
.expectStatus().isOk().expectBody(Session.class).isEqualTo(createdSession);
|
||||||
|
|
||||||
|
// WHEN
|
||||||
|
Thread.sleep(expirationInSeconds * 1000);
|
||||||
|
webTestClient.get().uri(String.format(V1_GET_SESSION_BY_ID_ENDPOINT_TEMPLATE, createdSession.getId())).exchange()
|
||||||
|
// THEN
|
||||||
|
.expectStatus().isNotFound();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package com.baelding.springbootredis.config;
|
||||||
|
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import jakarta.annotation.PreDestroy;
|
||||||
|
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
|
||||||
|
import org.springframework.boot.test.context.TestConfiguration;
|
||||||
|
import redis.embedded.RedisServer;
|
||||||
|
|
||||||
|
@TestConfiguration
|
||||||
|
public class RedisTestConfiguration {
|
||||||
|
|
||||||
|
private final RedisServer redisServer;
|
||||||
|
|
||||||
|
public RedisTestConfiguration(RedisProperties redisProperties) {
|
||||||
|
this.redisServer = new RedisServer(redisProperties.getPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void postConstruct() {
|
||||||
|
redisServer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void preDestroy() {
|
||||||
|
redisServer.stop();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue