From ffe7fd39e638b2a7ab7e2faf62a170bbb0e9b4ca Mon Sep 17 00:00:00 2001 From: Marcus Da Coregio Date: Tue, 6 Jun 2023 14:01:16 -0300 Subject: [PATCH] Ignore failed rename operation when key does not exists in Reactive Closes gh-2281 --- .../ReactiveRedisSessionRepositoryITests.java | 32 ++++++++++++++++++- .../redis/ReactiveRedisSessionRepository.java | 9 ++++-- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/spring-session-data-redis/src/integration-test/java/org/springframework/session/data/redis/ReactiveRedisSessionRepositoryITests.java b/spring-session-data-redis/src/integration-test/java/org/springframework/session/data/redis/ReactiveRedisSessionRepositoryITests.java index c58a9670..ded40a9b 100644 --- a/spring-session-data-redis/src/integration-test/java/org/springframework/session/data/redis/ReactiveRedisSessionRepositoryITests.java +++ b/spring-session-data-redis/src/integration-test/java/org/springframework/session/data/redis/ReactiveRedisSessionRepositoryITests.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2019 the original author or authors. + * Copyright 2014-2023 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. @@ -24,15 +24,21 @@ import reactor.core.publisher.Mono; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.core.ReactiveRedisOperations; import org.springframework.session.Session; import org.springframework.session.data.redis.ReactiveRedisSessionRepository.RedisSession; import org.springframework.session.data.redis.config.annotation.web.server.EnableRedisWebSession; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalStateException; +import static org.mockito.ArgumentMatchers.endsWith; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; /** * Integration tests for {@link ReactiveRedisSessionRepository}. @@ -215,6 +221,30 @@ class ReactiveRedisSessionRepositoryITests extends AbstractRedisITests { assertThat(this.repository.findById(session.getId()).block()).isNotNull(); } + // gh-2281 + @Test + @SuppressWarnings("unchecked") + void saveChangeSessionIdAfterCheckWhenOriginalKeyDoesNotExistsThenIgnoreError() { + ReactiveRedisOperations sessionRedisOperations = (ReactiveRedisOperations) ReflectionTestUtils + .getField(this.repository, "sessionRedisOperations"); + ReactiveRedisOperations spyOperations = spy(sessionRedisOperations); + ReflectionTestUtils.setField(this.repository, "sessionRedisOperations", spyOperations); + + RedisSession toSave = this.repository.createSession().block(); + String sessionId = toSave.getId(); + + given(spyOperations.hasKey(endsWith(sessionId))).willReturn(Mono.just(true)); + + this.repository.save(toSave).block(); + RedisSession session = this.repository.findById(sessionId).block(); + this.repository.deleteById(sessionId).block(); + String newSessionId = session.changeSessionId(); + this.repository.save(session).block(); + assertThat(this.repository.findById(sessionId).block()).isNull(); + assertThat(this.repository.findById(newSessionId).block()).isNull(); + reset(spyOperations); + } + @Configuration @EnableRedisWebSession static class Config extends BaseConfig { diff --git a/spring-session-data-redis/src/main/java/org/springframework/session/data/redis/ReactiveRedisSessionRepository.java b/spring-session-data-redis/src/main/java/org/springframework/session/data/redis/ReactiveRedisSessionRepository.java index a987359e..13fc623f 100644 --- a/spring-session-data-redis/src/main/java/org/springframework/session/data/redis/ReactiveRedisSessionRepository.java +++ b/spring-session-data-redis/src/main/java/org/springframework/session/data/redis/ReactiveRedisSessionRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2021 the original author or authors. + * Copyright 2014-2023 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. @@ -25,12 +25,14 @@ import java.util.Set; import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; +import org.springframework.core.NestedExceptionUtils; import org.springframework.data.redis.core.ReactiveRedisOperations; import org.springframework.session.MapSession; import org.springframework.session.ReactiveSessionRepository; import org.springframework.session.SaveMode; import org.springframework.session.Session; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; /** * A {@link ReactiveSessionRepository} that is implemented using Spring Data's @@ -310,7 +312,10 @@ public class ReactiveRedisSessionRepository String sessionKey = getSessionKey(sessionId); return ReactiveRedisSessionRepository.this.sessionRedisOperations.rename(originalSessionKey, sessionKey) - .and(replaceSessionId); + .and(replaceSessionId).onErrorResume((ex) -> { + String message = NestedExceptionUtils.getMostSpecificCause(ex).getMessage(); + return StringUtils.startsWithIgnoreCase(message, "ERR no such key"); + }, (ex) -> Mono.empty()); } }