From a3195f1f4b5219db6da166f3d179a475640f0c37 Mon Sep 17 00:00:00 2001 From: Vedran Pavic Date: Thu, 12 Apr 2018 22:00:03 +0200 Subject: [PATCH] Fix NPE in RedisOperationsSessionRepository event handling Closes gh-1049 --- .../RedisOperationsSessionRepository.java | 3 +- ...RedisOperationsSessionRepositoryTests.java | 101 +++++++++++++++++- 2 files changed, 101 insertions(+), 3 deletions(-) diff --git a/spring-session/src/main/java/org/springframework/session/data/redis/RedisOperationsSessionRepository.java b/spring-session/src/main/java/org/springframework/session/data/redis/RedisOperationsSessionRepository.java index cdf79662..8f912bc5 100644 --- a/spring-session/src/main/java/org/springframework/session/data/redis/RedisOperationsSessionRepository.java +++ b/spring-session/src/main/java/org/springframework/session/data/redis/RedisOperationsSessionRepository.java @@ -521,6 +521,7 @@ public class RedisOperationsSessionRepository implements if (session == null) { logger.warn("Unable to publish SessionDestroyedEvent for session " + sessionId); + return; } if (logger.isDebugEnabled()) { @@ -535,8 +536,6 @@ public class RedisOperationsSessionRepository implements else { handleExpired(session); } - - return; } } diff --git a/spring-session/src/test/java/org/springframework/session/data/redis/RedisOperationsSessionRepositoryTests.java b/spring-session/src/test/java/org/springframework/session/data/redis/RedisOperationsSessionRepositoryTests.java index 035a29a5..af299816 100644 --- a/spring-session/src/test/java/org/springframework/session/data/redis/RedisOperationsSessionRepositoryTests.java +++ b/spring-session/src/test/java/org/springframework/session/data/redis/RedisOperationsSessionRepositoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2016 the original author or authors. + * Copyright 2014-2018 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. @@ -59,6 +59,7 @@ import static org.mockito.BDDMockito.given; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; @@ -529,6 +530,104 @@ public class RedisOperationsSessionRepositoryTests { verify(this.defaultSerializer).deserialize(body); } + @Test + public void onMessageDeletedSessionFound() throws Exception { + String deletedId = "deleted-id"; + given(this.redisOperations.boundHashOps(getKey(deletedId))) + .willReturn(this.boundHashOperations); + Map map = map(RedisOperationsSessionRepository.MAX_INACTIVE_ATTR, 0, + RedisOperationsSessionRepository.LAST_ACCESSED_ATTR, + System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(5)); + given(this.boundHashOperations.entries()).willReturn(map); + + String channel = "__keyevent@0__:del"; + String body = "spring:session:sessions:expires:" + deletedId; + DefaultMessage message = new DefaultMessage(channel.getBytes("UTF-8"), body.getBytes("UTF-8")); + + this.redisRepository.setApplicationEventPublisher(this.publisher); + this.redisRepository.onMessage(message, "".getBytes("UTF-8")); + + verify(this.redisOperations).boundHashOps(eq(getKey(deletedId))); + verify(this.boundHashOperations).entries(); + verify(this.publisher).publishEvent(this.event.capture()); + assertThat(this.event.getValue().getSessionId()).isEqualTo(deletedId); + verifyZeroInteractions(this.defaultSerializer); + verifyZeroInteractions(this.publisher); + verifyZeroInteractions(this.redisOperations); + verifyZeroInteractions(this.boundHashOperations); + } + + @Test + public void onMessageDeletedSessionNotFound() throws Exception { + String deletedId = "deleted-id"; + given(this.redisOperations.boundHashOps(getKey(deletedId))) + .willReturn(this.boundHashOperations); + given(this.boundHashOperations.entries()).willReturn(map()); + + String channel = "__keyevent@0__:del"; + String body = "spring:session:sessions:expires:" + deletedId; + DefaultMessage message = new DefaultMessage(channel.getBytes("UTF-8"), body.getBytes("UTF-8")); + + this.redisRepository.setApplicationEventPublisher(this.publisher); + this.redisRepository.onMessage(message, "".getBytes("UTF-8")); + + verify(this.redisOperations).boundHashOps(eq(getKey(deletedId))); + verify(this.boundHashOperations).entries(); + verifyZeroInteractions(this.defaultSerializer); + verifyZeroInteractions(this.publisher); + verifyZeroInteractions(this.redisOperations); + verifyZeroInteractions(this.boundHashOperations); + } + + @Test + public void onMessageExpiredSessionFound() throws Exception { + String expiredId = "expired-id"; + given(this.redisOperations.boundHashOps(getKey(expiredId))) + .willReturn(this.boundHashOperations); + Map map = map(RedisOperationsSessionRepository.MAX_INACTIVE_ATTR, 1, + RedisOperationsSessionRepository.LAST_ACCESSED_ATTR, + System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(5)); + given(this.boundHashOperations.entries()).willReturn(map); + + String channel = "__keyevent@0__:expired"; + String body = "spring:session:sessions:expires:" + expiredId; + DefaultMessage message = new DefaultMessage(channel.getBytes("UTF-8"), body.getBytes("UTF-8")); + + this.redisRepository.setApplicationEventPublisher(this.publisher); + this.redisRepository.onMessage(message, "".getBytes("UTF-8")); + + verify(this.redisOperations).boundHashOps(eq(getKey(expiredId))); + verify(this.boundHashOperations).entries(); + verify(this.publisher).publishEvent(this.event.capture()); + assertThat(this.event.getValue().getSessionId()).isEqualTo(expiredId); + verifyZeroInteractions(this.defaultSerializer); + verifyZeroInteractions(this.publisher); + verifyZeroInteractions(this.redisOperations); + verifyZeroInteractions(this.boundHashOperations); + } + + @Test + public void onMessageExpiredSessionNotFound() throws Exception { + String expiredId = "expired-id"; + given(this.redisOperations.boundHashOps(getKey(expiredId))) + .willReturn(this.boundHashOperations); + given(this.boundHashOperations.entries()).willReturn(map()); + + String channel = "__keyevent@0__:expired"; + String body = "spring:session:sessions:expires:" + expiredId; + DefaultMessage message = new DefaultMessage(channel.getBytes("UTF-8"), body.getBytes("UTF-8")); + + this.redisRepository.setApplicationEventPublisher(this.publisher); + this.redisRepository.onMessage(message, "".getBytes("UTF-8")); + + verify(this.redisOperations).boundHashOps(eq(getKey(expiredId))); + verify(this.boundHashOperations).entries(); + verifyZeroInteractions(this.defaultSerializer); + verifyZeroInteractions(this.publisher); + verifyZeroInteractions(this.redisOperations); + verifyZeroInteractions(this.boundHashOperations); + } + @Test public void resolvePrincipalIndex() { PrincipalNameResolver resolver = RedisOperationsSessionRepository.PRINCIPAL_NAME_RESOLVER;