1+ /*
2+ * Copyright 2024 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+ */
116package org .springframework .data .redis .core ;
217
3- import org .junit .jupiter .api .BeforeEach ;
18+ import static org .assertj .core .api .Assertions .assertThat ;
19+ import static org .mockito .ArgumentMatchers .any ;
20+ import static org .mockito .ArgumentMatchers .eq ;
21+ import static org .mockito .Mockito .times ;
22+ import static org .mockito .Mockito .verify ;
23+ import static org .mockito .Mockito .when ;
24+
25+ import java .util .ArrayList ;
26+ import java .util .List ;
27+
428import org .junit .jupiter .api .Test ;
529import org .junit .jupiter .api .extension .ExtendWith ;
630import org .mockito .Mock ;
7- import org .mockito .MockitoAnnotations ;
31+ import org .mockito .Mockito ;
832import org .mockito .junit .jupiter .MockitoExtension ;
933import org .mockito .junit .jupiter .MockitoSettings ;
1034import org .mockito .quality .Strictness ;
11- import org .springframework .context .ApplicationEvent ;
12- import org .springframework .context .ApplicationEventPublisher ;
1335import org .springframework .core .convert .ConversionService ;
1436import org .springframework .data .redis .connection .Message ;
1537import org .springframework .data .redis .core .convert .RedisConverter ;
1638import org .springframework .data .redis .listener .RedisMessageListenerContainer ;
1739
18- import java .util .ArrayList ;
19- import java .util .List ;
20-
21- import static org .assertj .core .api .Assertions .assertThat ;
22- import static org .mockito .ArgumentMatchers .any ;
23- import static org .mockito .Mockito .*;
2440/**
2541 * @author Lucian Torje
42+ * @author Christoph Strobl
2643 */
2744@ ExtendWith (MockitoExtension .class )
2845@ MockitoSettings (strictness = Strictness .LENIENT )
2946class MappingExpirationListenerTest {
3047
31- @ Mock
32- private RedisOperations <?, ?> redisOperations ;
33- @ Mock
34- private RedisConverter redisConverter ;
35- @ Mock
36- private RedisMessageListenerContainer listenerContainer ;
37- @ Mock
38- private Message message ;
39- @ Mock
40- private RedisKeyExpiredEvent <?> event ;
41- @ Mock
42- private ConversionService conversionService ;
43-
44- private RedisKeyValueAdapter .MappingExpirationListener listener ;
45-
46- @ Test
47- void testOnNonKeyExpiration () {
48- byte [] key = "testKey" .getBytes ();
49- when (message .getBody ()).thenReturn (key );
50- listener = new RedisKeyValueAdapter .MappingExpirationListener (listenerContainer , redisOperations , redisConverter , RedisKeyValueAdapter .ShadowCopy .ON );
51-
52- listener .onMessage (message , null );
53-
54- verify (redisOperations , times (0 )).execute (any (RedisCallback .class ));
55- }
56-
57- @ Test
58- void testOnValidKeyExpiration () {
59- List <Object > eventList = new ArrayList <>();
60-
61- byte [] key = "abc:testKey" .getBytes ();
62- when (message .getBody ()).thenReturn (key );
63-
64- listener = new RedisKeyValueAdapter .MappingExpirationListener (listenerContainer , redisOperations , redisConverter , RedisKeyValueAdapter .ShadowCopy .OFF );
65- listener .setApplicationEventPublisher (eventList ::add );
66- listener .onMessage (message , null );
67-
68- verify (redisOperations , times (1 )).execute (any (RedisCallback .class ));
69- assertThat (eventList ).hasSize (1 );
70- assertThat (eventList .get (0 )).isInstanceOf (RedisKeyExpiredEvent .class );
71- assertThat (((RedisKeyExpiredEvent ) (eventList .get (0 ))).getKeyspace ()).isEqualTo ("abc" );
72- assertThat (((RedisKeyExpiredEvent ) (eventList .get (0 ))).getId ()).isEqualTo ("testKey" .getBytes ());
73- }
74- }
48+ @ Mock private RedisOperations <?, ?> redisOperations ;
49+ @ Mock private RedisConverter redisConverter ;
50+ @ Mock private RedisMessageListenerContainer listenerContainer ;
51+ @ Mock private Message message ;
52+
53+ private RedisKeyValueAdapter .MappingExpirationListener listener ;
54+
55+ @ Test // GH-2954
56+ void testOnNonKeyExpiration () {
57+
58+ byte [] key = "testKey" .getBytes ();
59+ when (message .getBody ()).thenReturn (key );
60+ listener = new RedisKeyValueAdapter .MappingExpirationListener (listenerContainer , redisOperations , redisConverter ,
61+ RedisKeyValueAdapter .ShadowCopy .ON );
62+
63+ listener .onMessage (message , null );
64+
65+ verify (redisOperations , times (0 )).execute (any (RedisCallback .class ));
66+ }
67+
68+ @ Test // GH-2954
69+ void testOnValidKeyExpirationWithShadowCopiesDisabled () {
70+
71+ List <Object > eventList = new ArrayList <>();
72+
73+ byte [] key = "abc:testKey" .getBytes ();
74+ when (message .getBody ()).thenReturn (key );
75+
76+ listener = new RedisKeyValueAdapter .MappingExpirationListener (listenerContainer , redisOperations , redisConverter ,
77+ RedisKeyValueAdapter .ShadowCopy .OFF );
78+ listener .setApplicationEventPublisher (eventList ::add );
79+ listener .onMessage (message , null );
80+
81+ verify (redisOperations , times (1 )).execute (any (RedisCallback .class ));
82+ assertThat (eventList ).hasSize (1 );
83+ assertThat (eventList .get (0 )).isInstanceOf (RedisKeyExpiredEvent .class );
84+ assertThat (((RedisKeyExpiredEvent ) (eventList .get (0 ))).getKeyspace ()).isEqualTo ("abc" );
85+ assertThat (((RedisKeyExpiredEvent ) (eventList .get (0 ))).getId ()).isEqualTo ("testKey" .getBytes ());
86+ }
87+
88+ @ Test // GH-2954
89+ void testOnValidKeyExpirationWithShadowCopiesEnabled () {
90+
91+ ConversionService conversionService = Mockito .mock (ConversionService .class );
92+ List <Object > eventList = new ArrayList <>();
93+
94+ byte [] key = "abc:testKey" .getBytes ();
95+ when (message .getBody ()).thenReturn (key );
96+ when (redisConverter .getConversionService ()).thenReturn (conversionService );
97+ when (conversionService .convert (any (), eq (byte [].class ))).thenReturn ("foo" .getBytes ());
98+
99+ listener = new RedisKeyValueAdapter .MappingExpirationListener (listenerContainer , redisOperations , redisConverter ,
100+ RedisKeyValueAdapter .ShadowCopy .ON );
101+ listener .setApplicationEventPublisher (eventList ::add );
102+ listener .onMessage (message , null );
103+
104+ verify (redisOperations , times (2 )).execute (any (RedisCallback .class )); // delete entry in index, delete phantom key
105+ assertThat (eventList ).hasSize (1 );
106+ assertThat (eventList .get (0 )).isInstanceOf (RedisKeyExpiredEvent .class );
107+ assertThat (((RedisKeyExpiredEvent ) (eventList .get (0 ))).getKeyspace ()).isEqualTo ("abc" );
108+ assertThat (((RedisKeyExpiredEvent ) (eventList .get (0 ))).getId ()).isEqualTo ("testKey" .getBytes ());
109+ }
110+ }
0 commit comments