Fix corrupt subscription connections return to pool
with Redis 2.6 Redis 2.6 responds to unsubscribe requests even if not subscribed. This results in unread data on the InputStream on Subscription close if extra unsubscribe requests are issued. This causes problems if connection is reused (as in the case of Jedis pool). - Only unsubscribe on Subscription close if still subscribed - Use dedicated connection for RJC subscriptions, as RJC makes extra unsubscribe calls on subscriber close
This commit is contained in:
@@ -0,0 +1,307 @@
|
||||
/*
|
||||
* Copyright 2011-2013 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.redis.connection.jedis;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import org.springframework.data.redis.connection.MessageListener;
|
||||
import org.springframework.data.redis.connection.RedisInvalidSubscriptionException;
|
||||
|
||||
import redis.clients.jedis.BinaryJedisPubSub;
|
||||
|
||||
/**
|
||||
* Unit test of {@link JedisSubscription}
|
||||
*
|
||||
* @author Jennifer Hickey
|
||||
*
|
||||
*/
|
||||
public class JedisSubscriptionTests {
|
||||
|
||||
private JedisSubscription subscription;
|
||||
|
||||
private BinaryJedisPubSub jedisPubSub;
|
||||
|
||||
private MessageListener listener;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
jedisPubSub = Mockito.mock(BinaryJedisPubSub.class);
|
||||
listener = Mockito.mock(MessageListener.class);
|
||||
subscription = new JedisSubscription(listener, jedisPubSub, null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeAllAndClose() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
verify(jedisPubSub, times(1)).unsubscribe();
|
||||
verify(jedisPubSub, never()).punsubscribe();
|
||||
assertFalse(subscription.isAlive());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeAllChannelsWithPatterns() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.pSubscribe(new byte[][] { "s*".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
verify(jedisPubSub, times(1)).unsubscribe();
|
||||
verify(jedisPubSub, never()).punsubscribe();
|
||||
assertTrue(subscription.isAlive());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
Collection<byte[]> patterns = subscription.getPatterns();
|
||||
assertEquals(1, patterns.size());
|
||||
assertArrayEquals("s*".getBytes(), patterns.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeChannelAndClose() {
|
||||
byte[][] channel = new byte[][] { "a".getBytes() };
|
||||
subscription.subscribe(channel);
|
||||
subscription.unsubscribe(channel);
|
||||
verify(jedisPubSub, times(1)).unsubscribe(channel);
|
||||
verify(jedisPubSub, never()).punsubscribe();
|
||||
assertFalse(subscription.isAlive());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeChannelSomeLeft() {
|
||||
byte[][] channels = new byte[][] { "a".getBytes(), "b".getBytes() };
|
||||
subscription.subscribe(channels);
|
||||
subscription.unsubscribe(new byte[][] { "a".getBytes() });
|
||||
verify(jedisPubSub, times(1)).unsubscribe(new byte[][] { "a".getBytes() });
|
||||
verify(jedisPubSub, never()).punsubscribe();
|
||||
assertTrue(subscription.isAlive());
|
||||
Collection<byte[]> subChannels = subscription.getChannels();
|
||||
assertEquals(1, subChannels.size());
|
||||
assertArrayEquals("b".getBytes(), subChannels.iterator().next());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeChannelWithPatterns() {
|
||||
byte[][] channel = new byte[][] { "a".getBytes() };
|
||||
subscription.subscribe(channel);
|
||||
subscription.pSubscribe(new byte[][] { "s*".getBytes() });
|
||||
subscription.unsubscribe(channel);
|
||||
verify(jedisPubSub, times(1)).unsubscribe(channel);
|
||||
verify(jedisPubSub, never()).punsubscribe();
|
||||
assertTrue(subscription.isAlive());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
Collection<byte[]> patterns = subscription.getPatterns();
|
||||
assertEquals(1, patterns.size());
|
||||
assertArrayEquals("s*".getBytes(), patterns.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeChannelWithPatternsSomeLeft() {
|
||||
byte[][] channel = new byte[][] { "a".getBytes() };
|
||||
subscription.subscribe(new byte[][] { "a".getBytes(), "b".getBytes() });
|
||||
subscription.pSubscribe(new byte[][] { "s*".getBytes() });
|
||||
subscription.unsubscribe(channel);
|
||||
verify(jedisPubSub, times(1)).unsubscribe(channel);
|
||||
verify(jedisPubSub, never()).punsubscribe();
|
||||
assertTrue(subscription.isAlive());
|
||||
Collection<byte[]> channels = subscription.getChannels();
|
||||
assertEquals(1, channels.size());
|
||||
assertArrayEquals("b".getBytes(), channels.iterator().next());
|
||||
Collection<byte[]> patterns = subscription.getPatterns();
|
||||
assertEquals(1, patterns.size());
|
||||
assertArrayEquals("s*".getBytes(), patterns.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeAllNoChannels() {
|
||||
subscription.pSubscribe(new byte[][] { "s*".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
verify(jedisPubSub, never()).unsubscribe();
|
||||
verify(jedisPubSub, never()).punsubscribe();
|
||||
assertTrue(subscription.isAlive());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
Collection<byte[]> patterns = subscription.getPatterns();
|
||||
assertEquals(1, patterns.size());
|
||||
assertArrayEquals("s*".getBytes(), patterns.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeNotAlive() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
assertFalse(subscription.isAlive());
|
||||
subscription.unsubscribe();
|
||||
verify(jedisPubSub, times(1)).unsubscribe();
|
||||
verify(jedisPubSub, never()).punsubscribe();
|
||||
}
|
||||
|
||||
@Test(expected = RedisInvalidSubscriptionException.class)
|
||||
public void testSubscribeNotAlive() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
assertFalse(subscription.isAlive());
|
||||
subscription.subscribe(new byte[][] { "s".getBytes() });
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribeAllAndClose() {
|
||||
subscription.pSubscribe(new byte[][] { "a*".getBytes() });
|
||||
subscription.pUnsubscribe();
|
||||
verify(jedisPubSub, never()).unsubscribe();
|
||||
verify(jedisPubSub, times(1)).punsubscribe();
|
||||
assertFalse(subscription.isAlive());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribeAllPatternsWithChannels() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.pSubscribe(new byte[][] { "s*".getBytes() });
|
||||
subscription.pUnsubscribe();
|
||||
verify(jedisPubSub, never()).unsubscribe();
|
||||
verify(jedisPubSub, times(1)).punsubscribe();
|
||||
assertTrue(subscription.isAlive());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
Collection<byte[]> channels = subscription.getChannels();
|
||||
assertEquals(1, channels.size());
|
||||
assertArrayEquals("a".getBytes(), channels.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribeAndClose() {
|
||||
byte[][] pattern = new byte[][] { "a*".getBytes() };
|
||||
subscription.pSubscribe(pattern);
|
||||
subscription.pUnsubscribe(pattern);
|
||||
verify(jedisPubSub, never()).unsubscribe();
|
||||
verify(jedisPubSub, times(1)).punsubscribe(pattern);
|
||||
assertFalse(subscription.isAlive());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribePatternSomeLeft() {
|
||||
byte[][] patterns = new byte[][] { "a*".getBytes(), "b*".getBytes() };
|
||||
subscription.pSubscribe(patterns);
|
||||
subscription.pUnsubscribe(new byte[][] { "a*".getBytes() });
|
||||
verify(jedisPubSub, times(1)).punsubscribe(new byte[][] { "a*".getBytes() });
|
||||
verify(jedisPubSub, never()).unsubscribe();
|
||||
assertTrue(subscription.isAlive());
|
||||
Collection<byte[]> subPatterns = subscription.getPatterns();
|
||||
assertEquals(1, subPatterns.size());
|
||||
assertArrayEquals("b*".getBytes(), subPatterns.iterator().next());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribePatternWithChannels() {
|
||||
byte[][] pattern = new byte[][] { "s*".getBytes() };
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.pSubscribe(pattern);
|
||||
subscription.pUnsubscribe(pattern);
|
||||
verify(jedisPubSub, times(1)).punsubscribe(pattern);
|
||||
verify(jedisPubSub, never()).unsubscribe();
|
||||
assertTrue(subscription.isAlive());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
Collection<byte[]> channels = subscription.getChannels();
|
||||
assertEquals(1, channels.size());
|
||||
assertArrayEquals("a".getBytes(), channels.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribePatternWithChannelsSomeLeft() {
|
||||
byte[][] pattern = new byte[][] { "a*".getBytes() };
|
||||
subscription.pSubscribe(new byte[][] { "a*".getBytes(), "b*".getBytes() });
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.pUnsubscribe(pattern);
|
||||
verify(jedisPubSub, never()).unsubscribe();
|
||||
verify(jedisPubSub, times(1)).punsubscribe(pattern);
|
||||
assertTrue(subscription.isAlive());
|
||||
Collection<byte[]> channels = subscription.getChannels();
|
||||
assertEquals(1, channels.size());
|
||||
assertArrayEquals("a".getBytes(), channels.iterator().next());
|
||||
Collection<byte[]> patterns = subscription.getPatterns();
|
||||
assertEquals(1, patterns.size());
|
||||
assertArrayEquals("b*".getBytes(), patterns.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribeAllNoPatterns() {
|
||||
subscription.subscribe(new byte[][] { "s".getBytes() });
|
||||
subscription.pUnsubscribe();
|
||||
verify(jedisPubSub, never()).unsubscribe();
|
||||
verify(jedisPubSub, never()).punsubscribe();
|
||||
assertTrue(subscription.isAlive());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
Collection<byte[]> channels = subscription.getChannels();
|
||||
assertEquals(1, channels.size());
|
||||
assertArrayEquals("s".getBytes(), channels.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribeNotAlive() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
assertFalse(subscription.isAlive());
|
||||
subscription.pUnsubscribe();
|
||||
verify(jedisPubSub, times(1)).unsubscribe();
|
||||
verify(jedisPubSub, never()).punsubscribe();
|
||||
}
|
||||
|
||||
@Test(expected = RedisInvalidSubscriptionException.class)
|
||||
public void testPSubscribeNotAlive() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
assertFalse(subscription.isAlive());
|
||||
subscription.pSubscribe(new byte[][] { "s*".getBytes() });
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoCloseNotSubscribed() {
|
||||
subscription.doClose();
|
||||
verify(jedisPubSub, never()).unsubscribe();
|
||||
verify(jedisPubSub, never()).punsubscribe();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoCloseSubscribedChannels() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.doClose();
|
||||
verify(jedisPubSub, times(1)).unsubscribe();
|
||||
verify(jedisPubSub, never()).punsubscribe();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoCloseSubscribedPatterns() {
|
||||
subscription.pSubscribe(new byte[][] { "a*".getBytes() });
|
||||
subscription.doClose();
|
||||
verify(jedisPubSub, never()).unsubscribe();
|
||||
verify(jedisPubSub, times(1)).punsubscribe();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* Copyright 2011-2013 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.redis.connection.lettuce;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.any;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.data.redis.connection.MessageListener;
|
||||
import org.springframework.data.redis.connection.RedisInvalidSubscriptionException;
|
||||
|
||||
import com.lambdaworks.redis.pubsub.RedisPubSubConnection;
|
||||
|
||||
/**
|
||||
* Unit test of {@link LettuceSubscription}
|
||||
*
|
||||
* @author Jennifer Hickey
|
||||
*
|
||||
*/
|
||||
public class LettuceSubscriptionTests {
|
||||
|
||||
private LettuceSubscription subscription;
|
||||
|
||||
RedisPubSubConnection<byte[], byte[]> pubsub;
|
||||
|
||||
private MessageListener listener;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Before
|
||||
public void setUp() {
|
||||
pubsub = Mockito.mock(RedisPubSubConnection.class);
|
||||
listener = Mockito.mock(MessageListener.class);
|
||||
subscription = new LettuceSubscription(listener, pubsub);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeAllAndClose() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
verify(pubsub, times(1)).unsubscribe(new byte[][] { "a".getBytes() });
|
||||
verify(pubsub, never()).unsubscribe(new byte[0]);
|
||||
verify(pubsub, never()).punsubscribe(new byte[0]);
|
||||
verify(pubsub).close();
|
||||
verify(pubsub).removeListener(any(LettuceMessageListener.class));
|
||||
assertFalse(subscription.isAlive());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeAllChannelsWithPatterns() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.pSubscribe(new byte[][] { "s*".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
verify(pubsub, times(1)).unsubscribe(new byte[][] { "a".getBytes() });
|
||||
verify(pubsub, never()).unsubscribe(new byte[0]);
|
||||
verify(pubsub, never()).punsubscribe(new byte[0]);
|
||||
assertTrue(subscription.isAlive());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
Collection<byte[]> patterns = subscription.getPatterns();
|
||||
assertEquals(1, patterns.size());
|
||||
assertArrayEquals("s*".getBytes(), patterns.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeChannelAndClose() {
|
||||
byte[][] channel = new byte[][] { "a".getBytes() };
|
||||
subscription.subscribe(channel);
|
||||
subscription.unsubscribe(channel);
|
||||
verify(pubsub, times(1)).unsubscribe(channel);
|
||||
verify(pubsub, never()).unsubscribe(new byte[0]);
|
||||
verify(pubsub, never()).punsubscribe(new byte[0]);
|
||||
verify(pubsub).close();
|
||||
verify(pubsub).removeListener(any(LettuceMessageListener.class));
|
||||
assertFalse(subscription.isAlive());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeChannelSomeLeft() {
|
||||
byte[][] channels = new byte[][] { "a".getBytes(), "b".getBytes() };
|
||||
subscription.subscribe(channels);
|
||||
subscription.unsubscribe(new byte[][] { "a".getBytes() });
|
||||
verify(pubsub, times(1)).unsubscribe(new byte[][] { "a".getBytes() });
|
||||
verify(pubsub, never()).unsubscribe(new byte[0]);
|
||||
verify(pubsub, never()).punsubscribe(new byte[0]);
|
||||
assertTrue(subscription.isAlive());
|
||||
Collection<byte[]> subChannels = subscription.getChannels();
|
||||
assertEquals(1, subChannels.size());
|
||||
assertArrayEquals("b".getBytes(), subChannels.iterator().next());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeChannelWithPatterns() {
|
||||
byte[][] channel = new byte[][] { "a".getBytes() };
|
||||
subscription.subscribe(channel);
|
||||
subscription.pSubscribe(new byte[][] { "s*".getBytes() });
|
||||
subscription.unsubscribe(channel);
|
||||
verify(pubsub, times(1)).unsubscribe(channel);
|
||||
verify(pubsub, never()).unsubscribe(new byte[0]);
|
||||
verify(pubsub, never()).punsubscribe(new byte[0]);
|
||||
assertTrue(subscription.isAlive());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
Collection<byte[]> patterns = subscription.getPatterns();
|
||||
assertEquals(1, patterns.size());
|
||||
assertArrayEquals("s*".getBytes(), patterns.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeChannelWithPatternsSomeLeft() {
|
||||
byte[][] channel = new byte[][] { "a".getBytes() };
|
||||
subscription.subscribe(new byte[][] { "a".getBytes(), "b".getBytes() });
|
||||
subscription.pSubscribe(new byte[][] { "s*".getBytes() });
|
||||
subscription.unsubscribe(channel);
|
||||
verify(pubsub, times(1)).unsubscribe(channel);
|
||||
verify(pubsub, never()).unsubscribe(new byte[0]);
|
||||
verify(pubsub, never()).punsubscribe(new byte[0]);
|
||||
assertTrue(subscription.isAlive());
|
||||
Collection<byte[]> channels = subscription.getChannels();
|
||||
assertEquals(1, channels.size());
|
||||
assertArrayEquals("b".getBytes(), channels.iterator().next());
|
||||
Collection<byte[]> patterns = subscription.getPatterns();
|
||||
assertEquals(1, patterns.size());
|
||||
assertArrayEquals("s*".getBytes(), patterns.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeAllNoChannels() {
|
||||
subscription.pSubscribe(new byte[][] { "s*".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
verify(pubsub, never()).unsubscribe(new byte[0]);
|
||||
verify(pubsub, never()).punsubscribe(new byte[0]);
|
||||
assertTrue(subscription.isAlive());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
Collection<byte[]> patterns = subscription.getPatterns();
|
||||
assertEquals(1, patterns.size());
|
||||
assertArrayEquals("s*".getBytes(), patterns.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeNotAlive() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
verify(pubsub, times(1)).close();
|
||||
verify(pubsub, times(1)).removeListener(any(LettuceMessageListener.class));
|
||||
assertFalse(subscription.isAlive());
|
||||
subscription.unsubscribe();
|
||||
verify(pubsub, times(1)).unsubscribe(new byte[][] { "a".getBytes() });
|
||||
verify(pubsub, never()).unsubscribe(new byte[0]);
|
||||
verify(pubsub, never()).punsubscribe(new byte[0]);
|
||||
}
|
||||
|
||||
@Test(expected = RedisInvalidSubscriptionException.class)
|
||||
public void testSubscribeNotAlive() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
assertFalse(subscription.isAlive());
|
||||
subscription.subscribe(new byte[][] { "s".getBytes() });
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribeAllAndClose() {
|
||||
subscription.pSubscribe(new byte[][] { "a*".getBytes() });
|
||||
subscription.pUnsubscribe();
|
||||
verify(pubsub, never()).unsubscribe(new byte[0]);
|
||||
verify(pubsub, never()).punsubscribe(new byte[0]);
|
||||
verify(pubsub, times(1)).punsubscribe(new byte[][] { "a*".getBytes() });
|
||||
assertFalse(subscription.isAlive());
|
||||
verify(pubsub).close();
|
||||
verify(pubsub).removeListener(any(LettuceMessageListener.class));
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribeAllPatternsWithChannels() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.pSubscribe(new byte[][] { "s*".getBytes() });
|
||||
subscription.pUnsubscribe();
|
||||
verify(pubsub, never()).unsubscribe(new byte[0]);
|
||||
verify(pubsub, never()).punsubscribe(new byte[0]);
|
||||
verify(pubsub, times(1)).punsubscribe(new byte[][] { "s*".getBytes() });
|
||||
assertTrue(subscription.isAlive());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
Collection<byte[]> channels = subscription.getChannels();
|
||||
assertEquals(1, channels.size());
|
||||
assertArrayEquals("a".getBytes(), channels.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribeAndClose() {
|
||||
byte[][] pattern = new byte[][] { "a*".getBytes() };
|
||||
subscription.pSubscribe(pattern);
|
||||
subscription.pUnsubscribe(pattern);
|
||||
verify(pubsub, never()).unsubscribe(new byte[0]);
|
||||
verify(pubsub, never()).punsubscribe(new byte[0]);
|
||||
verify(pubsub, times(1)).punsubscribe(pattern);
|
||||
verify(pubsub).close();
|
||||
verify(pubsub).removeListener(any(LettuceMessageListener.class));
|
||||
assertFalse(subscription.isAlive());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribePatternSomeLeft() {
|
||||
byte[][] patterns = new byte[][] { "a*".getBytes(), "b*".getBytes() };
|
||||
subscription.pSubscribe(patterns);
|
||||
subscription.pUnsubscribe(new byte[][] { "a*".getBytes() });
|
||||
verify(pubsub, times(1)).punsubscribe(new byte[][] { "a*".getBytes() });
|
||||
verify(pubsub, never()).unsubscribe(new byte[0]);
|
||||
verify(pubsub, never()).punsubscribe(new byte[0]);
|
||||
assertTrue(subscription.isAlive());
|
||||
Collection<byte[]> subPatterns = subscription.getPatterns();
|
||||
assertEquals(1, subPatterns.size());
|
||||
assertArrayEquals("b*".getBytes(), subPatterns.iterator().next());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribePatternWithChannels() {
|
||||
byte[][] pattern = new byte[][] { "s*".getBytes() };
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.pSubscribe(pattern);
|
||||
subscription.pUnsubscribe(pattern);
|
||||
verify(pubsub, times(1)).punsubscribe(pattern);
|
||||
verify(pubsub, never()).unsubscribe(new byte[0]);
|
||||
verify(pubsub, never()).punsubscribe(new byte[0]);
|
||||
assertTrue(subscription.isAlive());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
Collection<byte[]> channels = subscription.getChannels();
|
||||
assertEquals(1, channels.size());
|
||||
assertArrayEquals("a".getBytes(), channels.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribePatternWithChannelsSomeLeft() {
|
||||
byte[][] pattern = new byte[][] { "a*".getBytes() };
|
||||
subscription.pSubscribe(new byte[][] { "a*".getBytes(), "b*".getBytes() });
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.pUnsubscribe(pattern);
|
||||
verify(pubsub, never()).unsubscribe(new byte[0]);
|
||||
verify(pubsub, never()).punsubscribe(new byte[0]);
|
||||
verify(pubsub, times(1)).punsubscribe(pattern);
|
||||
assertTrue(subscription.isAlive());
|
||||
Collection<byte[]> channels = subscription.getChannels();
|
||||
assertEquals(1, channels.size());
|
||||
assertArrayEquals("a".getBytes(), channels.iterator().next());
|
||||
Collection<byte[]> patterns = subscription.getPatterns();
|
||||
assertEquals(1, patterns.size());
|
||||
assertArrayEquals("b*".getBytes(), patterns.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribeAllNoPatterns() {
|
||||
subscription.subscribe(new byte[][] { "s".getBytes() });
|
||||
subscription.pUnsubscribe();
|
||||
verify(pubsub, never()).unsubscribe(new byte[0]);
|
||||
verify(pubsub, never()).punsubscribe(new byte[0]);
|
||||
assertTrue(subscription.isAlive());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
Collection<byte[]> channels = subscription.getChannels();
|
||||
assertEquals(1, channels.size());
|
||||
assertArrayEquals("s".getBytes(), channels.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribeNotAlive() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
assertFalse(subscription.isAlive());
|
||||
subscription.pUnsubscribe();
|
||||
verify(pubsub, times(1)).close();
|
||||
verify(pubsub, times(1)).removeListener(any(LettuceMessageListener.class));
|
||||
verify(pubsub, times(1)).unsubscribe(new byte[][] { "a".getBytes() });
|
||||
verify(pubsub, never()).unsubscribe(new byte[0]);
|
||||
verify(pubsub, never()).punsubscribe(new byte[0]);
|
||||
}
|
||||
|
||||
@Test(expected = RedisInvalidSubscriptionException.class)
|
||||
public void testPSubscribeNotAlive() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
assertFalse(subscription.isAlive());
|
||||
subscription.pSubscribe(new byte[][] { "s*".getBytes() });
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoCloseNotSubscribed() {
|
||||
subscription.doClose();
|
||||
verify(pubsub, never()).unsubscribe(new byte[0]);
|
||||
verify(pubsub, never()).punsubscribe(new byte[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoCloseSubscribedChannels() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.doClose();
|
||||
verify(pubsub, times(1)).unsubscribe(new byte[0]);
|
||||
verify(pubsub, never()).punsubscribe(new byte[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoCloseSubscribedPatterns() {
|
||||
subscription.pSubscribe(new byte[][] { "a*".getBytes() });
|
||||
subscription.doClose();
|
||||
verify(pubsub, never()).unsubscribe(new byte[0]);
|
||||
verify(pubsub, times(1)).punsubscribe(new byte[0]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright 2011-2013 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.redis.connection.rjc;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.idevlab.rjc.message.RedisNodeSubscriber;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.data.redis.connection.MessageListener;
|
||||
import org.springframework.data.redis.connection.RedisInvalidSubscriptionException;
|
||||
|
||||
/**
|
||||
* Unit test of {@link RjcSubscription}
|
||||
*
|
||||
* @author Jennifer Hickey
|
||||
*
|
||||
*/
|
||||
public class RjcSubscriptionTests {
|
||||
|
||||
private RjcSubscription subscription;
|
||||
|
||||
private RedisNodeSubscriber subscriber;
|
||||
|
||||
private MessageListener listener;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
subscriber = Mockito.mock(RedisNodeSubscriber.class);
|
||||
listener = Mockito.mock(MessageListener.class);
|
||||
subscription = new RjcSubscription(listener, subscriber);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeAllAndClose() {
|
||||
byte[][] channel = new byte[][] { "a".getBytes() };
|
||||
subscription.subscribe(channel);
|
||||
subscription.unsubscribe();
|
||||
verify(subscriber, never()).close();
|
||||
verify(subscriber, times(1)).unsubscribe(RjcUtils.decodeMultiple(channel));
|
||||
assertFalse(subscription.isAlive());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeAllChannelsWithPatterns() {
|
||||
byte[][] channel = new byte[][] { "a".getBytes() };
|
||||
subscription.subscribe(channel);
|
||||
subscription.pSubscribe(new byte[][] { "s*".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
verify(subscriber, times(1)).unsubscribe(RjcUtils.decodeMultiple(channel));
|
||||
verify(subscriber, never()).close();
|
||||
assertTrue(subscription.isAlive());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
Collection<byte[]> patterns = subscription.getPatterns();
|
||||
assertEquals(1, patterns.size());
|
||||
assertArrayEquals("s*".getBytes(), patterns.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeChannelAndClose() {
|
||||
byte[][] channel = new byte[][] { "a".getBytes() };
|
||||
subscription.subscribe(channel);
|
||||
subscription.unsubscribe(channel);
|
||||
verify(subscriber, times(1)).unsubscribe(RjcUtils.decodeMultiple(channel));
|
||||
verify(subscriber, never()).close();
|
||||
assertFalse(subscription.isAlive());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeChannelSomeLeft() {
|
||||
byte[][] channels = new byte[][] { "a".getBytes(), "b".getBytes() };
|
||||
subscription.subscribe(channels);
|
||||
subscription.unsubscribe(new byte[][] { "a".getBytes() });
|
||||
verify(subscriber, times(1)).unsubscribe(
|
||||
RjcUtils.decodeMultiple(new byte[][] { "a".getBytes() }));
|
||||
verify(subscriber, never()).close();
|
||||
assertTrue(subscription.isAlive());
|
||||
Collection<byte[]> subChannels = subscription.getChannels();
|
||||
assertEquals(1, subChannels.size());
|
||||
assertArrayEquals("b".getBytes(), subChannels.iterator().next());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeChannelWithPatterns() {
|
||||
byte[][] channel = new byte[][] { "a".getBytes() };
|
||||
subscription.subscribe(channel);
|
||||
subscription.pSubscribe(new byte[][] { "s*".getBytes() });
|
||||
subscription.unsubscribe(channel);
|
||||
verify(subscriber, times(1)).unsubscribe(RjcUtils.decodeMultiple(channel));
|
||||
verify(subscriber, never()).close();
|
||||
assertTrue(subscription.isAlive());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
Collection<byte[]> patterns = subscription.getPatterns();
|
||||
assertEquals(1, patterns.size());
|
||||
assertArrayEquals("s*".getBytes(), patterns.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeChannelWithPatternsSomeLeft() {
|
||||
byte[][] channel = new byte[][] { "a".getBytes() };
|
||||
subscription.subscribe(new byte[][] { "a".getBytes(), "b".getBytes() });
|
||||
subscription.pSubscribe(new byte[][] { "s*".getBytes() });
|
||||
subscription.unsubscribe(channel);
|
||||
verify(subscriber, times(1)).unsubscribe(RjcUtils.decodeMultiple(channel));
|
||||
verify(subscriber, never()).close();
|
||||
assertTrue(subscription.isAlive());
|
||||
Collection<byte[]> channels = subscription.getChannels();
|
||||
assertEquals(1, channels.size());
|
||||
assertArrayEquals("b".getBytes(), channels.iterator().next());
|
||||
Collection<byte[]> patterns = subscription.getPatterns();
|
||||
assertEquals(1, patterns.size());
|
||||
assertArrayEquals("s*".getBytes(), patterns.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeAllNoChannels() {
|
||||
subscription.pSubscribe(new byte[][] { "s*".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
verify(subscriber, never()).close();
|
||||
assertTrue(subscription.isAlive());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
Collection<byte[]> patterns = subscription.getPatterns();
|
||||
assertEquals(1, patterns.size());
|
||||
assertArrayEquals("s*".getBytes(), patterns.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeNotAlive() {
|
||||
byte[][] channel = new byte[][] { "a".getBytes() };
|
||||
subscription.subscribe(channel);
|
||||
subscription.unsubscribe();
|
||||
assertFalse(subscription.isAlive());
|
||||
subscription.unsubscribe();
|
||||
verify(subscriber, times(1)).unsubscribe(RjcUtils.decodeMultiple(channel));
|
||||
verify(subscriber, never()).close();
|
||||
}
|
||||
|
||||
@Test(expected = RedisInvalidSubscriptionException.class)
|
||||
public void testSubscribeNotAlive() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
assertFalse(subscription.isAlive());
|
||||
subscription.subscribe(new byte[][] { "s".getBytes() });
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribeAllAndClose() {
|
||||
byte[][] pattern = new byte[][] { "a*".getBytes() };
|
||||
subscription.pSubscribe(pattern);
|
||||
subscription.pUnsubscribe();
|
||||
verify(subscriber, never()).close();
|
||||
verify(subscriber, times(1)).punsubscribe(RjcUtils.decodeMultiple(pattern));
|
||||
assertFalse(subscription.isAlive());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribeAllPatternsWithChannels() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
byte[][] patterns = new byte[][] { "s*".getBytes() };
|
||||
subscription.pSubscribe(patterns);
|
||||
subscription.pUnsubscribe();
|
||||
verify(subscriber, never()).close();
|
||||
verify(subscriber, times(1)).punsubscribe(RjcUtils.decodeMultiple(patterns));
|
||||
assertTrue(subscription.isAlive());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
Collection<byte[]> channels = subscription.getChannels();
|
||||
assertEquals(1, channels.size());
|
||||
assertArrayEquals("a".getBytes(), channels.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribeAndClose() {
|
||||
byte[][] pattern = new byte[][] { "a*".getBytes() };
|
||||
subscription.pSubscribe(pattern);
|
||||
subscription.pUnsubscribe(pattern);
|
||||
verify(subscriber, never()).close();
|
||||
verify(subscriber, times(1)).punsubscribe(RjcUtils.decodeMultiple(pattern));
|
||||
assertFalse(subscription.isAlive());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribePatternSomeLeft() {
|
||||
byte[][] patterns = new byte[][] { "a*".getBytes(), "b*".getBytes() };
|
||||
subscription.pSubscribe(patterns);
|
||||
byte[][] pattern = new byte[][] { "a*".getBytes() };
|
||||
subscription.pUnsubscribe(pattern);
|
||||
verify(subscriber, times(1)).punsubscribe(RjcUtils.decodeMultiple(pattern));
|
||||
verify(subscriber, never()).close();
|
||||
assertTrue(subscription.isAlive());
|
||||
Collection<byte[]> subPatterns = subscription.getPatterns();
|
||||
assertEquals(1, subPatterns.size());
|
||||
assertArrayEquals("b*".getBytes(), subPatterns.iterator().next());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribePatternWithChannels() {
|
||||
byte[][] pattern = new byte[][] { "s*".getBytes() };
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.pSubscribe(pattern);
|
||||
subscription.pUnsubscribe(pattern);
|
||||
verify(subscriber, times(1)).punsubscribe(RjcUtils.decodeMultiple(pattern));
|
||||
verify(subscriber, never()).close();
|
||||
assertTrue(subscription.isAlive());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
Collection<byte[]> channels = subscription.getChannels();
|
||||
assertEquals(1, channels.size());
|
||||
assertArrayEquals("a".getBytes(), channels.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribePatternWithChannelsSomeLeft() {
|
||||
byte[][] pattern = new byte[][] { "a*".getBytes() };
|
||||
subscription.pSubscribe(new byte[][] { "a*".getBytes(), "b*".getBytes() });
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.pUnsubscribe(pattern);
|
||||
verify(subscriber, never()).close();
|
||||
verify(subscriber, times(1)).punsubscribe(RjcUtils.decodeMultiple(pattern));
|
||||
assertTrue(subscription.isAlive());
|
||||
Collection<byte[]> channels = subscription.getChannels();
|
||||
assertEquals(1, channels.size());
|
||||
assertArrayEquals("a".getBytes(), channels.iterator().next());
|
||||
Collection<byte[]> patterns = subscription.getPatterns();
|
||||
assertEquals(1, patterns.size());
|
||||
assertArrayEquals("b*".getBytes(), patterns.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribeAllNoPatterns() {
|
||||
subscription.subscribe(new byte[][] { "s".getBytes() });
|
||||
subscription.pUnsubscribe();
|
||||
verify(subscriber, never()).close();
|
||||
assertTrue(subscription.isAlive());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
Collection<byte[]> channels = subscription.getChannels();
|
||||
assertEquals(1, channels.size());
|
||||
assertArrayEquals("s".getBytes(), channels.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribeNotAlive() {
|
||||
byte[][] channels = new byte[][] { "a".getBytes() };
|
||||
subscription.subscribe(channels);
|
||||
subscription.unsubscribe();
|
||||
assertFalse(subscription.isAlive());
|
||||
subscription.pUnsubscribe();
|
||||
verify(subscriber, times(1)).unsubscribe(RjcUtils.decodeMultiple(channels));
|
||||
verify(subscriber, never()).close();
|
||||
}
|
||||
|
||||
@Test(expected = RedisInvalidSubscriptionException.class)
|
||||
public void testPSubscribeNotAlive() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
assertFalse(subscription.isAlive());
|
||||
subscription.pSubscribe(new byte[][] { "s*".getBytes() });
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoCloseNotSubscribed() {
|
||||
subscription.doClose();
|
||||
verify(subscriber, never()).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoCloseSubscribedChannels() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.doClose();
|
||||
verify(subscriber, times(1)).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoCloseSubscribedPatterns() {
|
||||
subscription.pSubscribe(new byte[][] { "a*".getBytes() });
|
||||
subscription.doClose();
|
||||
verify(subscriber, times(1)).close();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* Copyright 2011-2013 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.redis.connection.srp;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.any;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.data.redis.connection.MessageListener;
|
||||
import org.springframework.data.redis.connection.RedisInvalidSubscriptionException;
|
||||
|
||||
import redis.client.RedisClient;
|
||||
import redis.client.ReplyListener;
|
||||
|
||||
/**
|
||||
* Unit test of {@link SrpSubscription}
|
||||
*
|
||||
* @author Jennifer Hickey
|
||||
*
|
||||
*/
|
||||
public class SrpSubscriptionTests {
|
||||
|
||||
private SrpSubscription subscription;
|
||||
|
||||
private RedisClient redisClient;
|
||||
|
||||
private MessageListener listener;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
redisClient = Mockito.mock(RedisClient.class);
|
||||
listener = Mockito.mock(MessageListener.class);
|
||||
subscription = new SrpSubscription(listener, redisClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeAllAndClose() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
verify(redisClient, times(1)).unsubscribe((Object[]) null);
|
||||
verify(redisClient, never()).punsubscribe((Object[]) null);
|
||||
assertFalse(subscription.isAlive());
|
||||
verify(redisClient).removeListener(any(ReplyListener.class));
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeAllChannelsWithPatterns() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.pSubscribe(new byte[][] { "s*".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
verify(redisClient, times(1)).unsubscribe((Object[]) null);
|
||||
verify(redisClient, never()).punsubscribe((Object[]) null);
|
||||
assertTrue(subscription.isAlive());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
Collection<byte[]> patterns = subscription.getPatterns();
|
||||
assertEquals(1, patterns.size());
|
||||
assertArrayEquals("s*".getBytes(), patterns.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeChannelAndClose() {
|
||||
byte[][] channel = new byte[][] { "a".getBytes() };
|
||||
subscription.subscribe(channel);
|
||||
subscription.unsubscribe(channel);
|
||||
verify(redisClient, times(1)).unsubscribe((Object[]) channel);
|
||||
verify(redisClient, never()).punsubscribe((Object[]) null);
|
||||
verify(redisClient).removeListener(any(ReplyListener.class));
|
||||
assertFalse(subscription.isAlive());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeChannelSomeLeft() {
|
||||
byte[][] channels = new byte[][] { "a".getBytes(), "b".getBytes() };
|
||||
subscription.subscribe(channels);
|
||||
subscription.unsubscribe(new byte[][] { "a".getBytes() });
|
||||
verify(redisClient, times(1)).unsubscribe((Object[]) new byte[][] { "a".getBytes() });
|
||||
verify(redisClient, never()).punsubscribe((Object[]) null);
|
||||
assertTrue(subscription.isAlive());
|
||||
Collection<byte[]> subChannels = subscription.getChannels();
|
||||
assertEquals(1, subChannels.size());
|
||||
assertArrayEquals("b".getBytes(), subChannels.iterator().next());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeChannelWithPatterns() {
|
||||
byte[][] channel = new byte[][] { "a".getBytes() };
|
||||
subscription.subscribe(channel);
|
||||
subscription.pSubscribe(new byte[][] { "s*".getBytes() });
|
||||
subscription.unsubscribe(channel);
|
||||
verify(redisClient, times(1)).unsubscribe((Object[]) channel);
|
||||
verify(redisClient, never()).punsubscribe((Object[]) null);
|
||||
assertTrue(subscription.isAlive());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
Collection<byte[]> patterns = subscription.getPatterns();
|
||||
assertEquals(1, patterns.size());
|
||||
assertArrayEquals("s*".getBytes(), patterns.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeChannelWithPatternsSomeLeft() {
|
||||
byte[][] channel = new byte[][] { "a".getBytes() };
|
||||
subscription.subscribe(new byte[][] { "a".getBytes(), "b".getBytes() });
|
||||
subscription.pSubscribe(new byte[][] { "s*".getBytes() });
|
||||
subscription.unsubscribe(channel);
|
||||
verify(redisClient, times(1)).unsubscribe((Object[]) channel);
|
||||
verify(redisClient, never()).punsubscribe((Object[]) null);
|
||||
assertTrue(subscription.isAlive());
|
||||
Collection<byte[]> channels = subscription.getChannels();
|
||||
assertEquals(1, channels.size());
|
||||
assertArrayEquals("b".getBytes(), channels.iterator().next());
|
||||
Collection<byte[]> patterns = subscription.getPatterns();
|
||||
assertEquals(1, patterns.size());
|
||||
assertArrayEquals("s*".getBytes(), patterns.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeAllNoChannels() {
|
||||
subscription.pSubscribe(new byte[][] { "s*".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
verify(redisClient, never()).unsubscribe((Object[]) null);
|
||||
verify(redisClient, never()).punsubscribe((Object[]) null);
|
||||
assertTrue(subscription.isAlive());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
Collection<byte[]> patterns = subscription.getPatterns();
|
||||
assertEquals(1, patterns.size());
|
||||
assertArrayEquals("s*".getBytes(), patterns.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeNotAlive() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
assertFalse(subscription.isAlive());
|
||||
subscription.unsubscribe();
|
||||
verify(redisClient, times(1)).removeListener(any(ReplyListener.class));
|
||||
verify(redisClient, times(1)).unsubscribe((Object[]) null);
|
||||
verify(redisClient, never()).punsubscribe((Object[]) null);
|
||||
}
|
||||
|
||||
@Test(expected = RedisInvalidSubscriptionException.class)
|
||||
public void testSubscribeNotAlive() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
assertFalse(subscription.isAlive());
|
||||
subscription.subscribe(new byte[][] { "s".getBytes() });
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribeAllAndClose() {
|
||||
subscription.pSubscribe(new byte[][] { "a*".getBytes() });
|
||||
subscription.pUnsubscribe();
|
||||
verify(redisClient, never()).unsubscribe((Object[]) null);
|
||||
verify(redisClient, times(1)).punsubscribe((Object[]) null);
|
||||
assertFalse(subscription.isAlive());
|
||||
verify(redisClient).removeListener(any(ReplyListener.class));
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribeAllPatternsWithChannels() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.pSubscribe(new byte[][] { "s*".getBytes() });
|
||||
subscription.pUnsubscribe();
|
||||
verify(redisClient, never()).unsubscribe((Object[]) null);
|
||||
verify(redisClient, times(1)).punsubscribe((Object[]) null);
|
||||
assertTrue(subscription.isAlive());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
Collection<byte[]> channels = subscription.getChannels();
|
||||
assertEquals(1, channels.size());
|
||||
assertArrayEquals("a".getBytes(), channels.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribeAndClose() {
|
||||
byte[][] pattern = new byte[][] { "a*".getBytes() };
|
||||
subscription.pSubscribe(pattern);
|
||||
subscription.pUnsubscribe(pattern);
|
||||
verify(redisClient, never()).unsubscribe((Object[]) null);
|
||||
verify(redisClient, times(1)).punsubscribe((Object[]) pattern);
|
||||
assertFalse(subscription.isAlive());
|
||||
verify(redisClient).removeListener(any(ReplyListener.class));
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribePatternSomeLeft() {
|
||||
byte[][] patterns = new byte[][] { "a*".getBytes(), "b*".getBytes() };
|
||||
subscription.pSubscribe(patterns);
|
||||
subscription.pUnsubscribe(new byte[][] { "a*".getBytes() });
|
||||
verify(redisClient, times(1)).punsubscribe((Object[]) new byte[][] { "a*".getBytes() });
|
||||
verify(redisClient, never()).unsubscribe((Object[]) null);
|
||||
assertTrue(subscription.isAlive());
|
||||
Collection<byte[]> subPatterns = subscription.getPatterns();
|
||||
assertEquals(1, subPatterns.size());
|
||||
assertArrayEquals("b*".getBytes(), subPatterns.iterator().next());
|
||||
assertTrue(subscription.getChannels().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribePatternWithChannels() {
|
||||
byte[][] pattern = new byte[][] { "s*".getBytes() };
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.pSubscribe(pattern);
|
||||
subscription.pUnsubscribe(pattern);
|
||||
verify(redisClient, times(1)).punsubscribe((Object[]) pattern);
|
||||
verify(redisClient, never()).unsubscribe((Object[]) null);
|
||||
assertTrue(subscription.isAlive());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
Collection<byte[]> channels = subscription.getChannels();
|
||||
assertEquals(1, channels.size());
|
||||
assertArrayEquals("a".getBytes(), channels.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribePatternWithChannelsSomeLeft() {
|
||||
byte[][] pattern = new byte[][] { "a*".getBytes() };
|
||||
subscription.pSubscribe(new byte[][] { "a*".getBytes(), "b*".getBytes() });
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.pUnsubscribe(pattern);
|
||||
verify(redisClient, never()).unsubscribe((Object[]) null);
|
||||
verify(redisClient, times(1)).punsubscribe((Object[]) pattern);
|
||||
assertTrue(subscription.isAlive());
|
||||
Collection<byte[]> channels = subscription.getChannels();
|
||||
assertEquals(1, channels.size());
|
||||
assertArrayEquals("a".getBytes(), channels.iterator().next());
|
||||
Collection<byte[]> patterns = subscription.getPatterns();
|
||||
assertEquals(1, patterns.size());
|
||||
assertArrayEquals("b*".getBytes(), patterns.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribeAllNoPatterns() {
|
||||
subscription.subscribe(new byte[][] { "s".getBytes() });
|
||||
subscription.pUnsubscribe();
|
||||
verify(redisClient, never()).unsubscribe((Object[]) null);
|
||||
verify(redisClient, never()).punsubscribe((Object[]) null);
|
||||
assertTrue(subscription.isAlive());
|
||||
assertTrue(subscription.getPatterns().isEmpty());
|
||||
Collection<byte[]> channels = subscription.getChannels();
|
||||
assertEquals(1, channels.size());
|
||||
assertArrayEquals("s".getBytes(), channels.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUnsubscribeNotAlive() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
assertFalse(subscription.isAlive());
|
||||
subscription.pUnsubscribe();
|
||||
verify(redisClient, times(1)).unsubscribe((Object[]) null);
|
||||
verify(redisClient, never()).punsubscribe((Object[]) null);
|
||||
verify(redisClient, times(1)).removeListener(any(ReplyListener.class));
|
||||
}
|
||||
|
||||
@Test(expected = RedisInvalidSubscriptionException.class)
|
||||
public void testPSubscribeNotAlive() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.unsubscribe();
|
||||
assertFalse(subscription.isAlive());
|
||||
subscription.pSubscribe(new byte[][] { "s*".getBytes() });
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoCloseNotSubscribed() {
|
||||
subscription.doClose();
|
||||
verify(redisClient, never()).unsubscribe((Object[]) null);
|
||||
verify(redisClient, never()).punsubscribe((Object[]) null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoCloseSubscribedChannels() {
|
||||
subscription.subscribe(new byte[][] { "a".getBytes() });
|
||||
subscription.doClose();
|
||||
verify(redisClient, times(1)).unsubscribe((Object[]) null);
|
||||
verify(redisClient, never()).punsubscribe((Object[]) null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoCloseSubscribedPatterns() {
|
||||
subscription.pSubscribe(new byte[][] { "a*".getBytes() });
|
||||
subscription.doClose();
|
||||
verify(redisClient, never()).unsubscribe((Object[]) null);
|
||||
verify(redisClient, times(1)).punsubscribe((Object[]) null);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,21 +17,28 @@ package org.springframework.data.redis.listener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.core.task.SyncTaskExecutor;
|
||||
import org.springframework.data.redis.ConnectionFactoryTracker;
|
||||
import org.springframework.data.redis.SettingsUtils;
|
||||
import org.springframework.data.redis.connection.MessageListener;
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.data.redis.connection.rjc.RjcConnectionFactory;
|
||||
import org.springframework.data.redis.connection.srp.SrpConnectionFactory;
|
||||
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
|
||||
|
||||
import redis.clients.jedis.JedisPoolConfig;
|
||||
|
||||
/**
|
||||
* Integration tests confirming that {@link RedisMessageListenerContainer}
|
||||
* closes connections after unsubscribing
|
||||
@@ -39,11 +46,12 @@ import redis.clients.jedis.JedisPoolConfig;
|
||||
* @author Jennifer Hickey
|
||||
*
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class SubscriptionConnectionTests {
|
||||
|
||||
private static final String CHANNEL = "pubsub::test";
|
||||
|
||||
private JedisConnectionFactory connectionFactory;
|
||||
private RedisConnectionFactory connectionFactory;
|
||||
|
||||
private List<RedisMessageListenerContainer> containers = new ArrayList<RedisMessageListenerContainer>();
|
||||
|
||||
@@ -54,17 +62,9 @@ public class SubscriptionConnectionTests {
|
||||
}
|
||||
};
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
connectionFactory = new JedisConnectionFactory();
|
||||
connectionFactory.setUsePool(true);
|
||||
connectionFactory.setPort(SettingsUtils.getPort());
|
||||
connectionFactory.setHostName(SettingsUtils.getHost());
|
||||
connectionFactory.setDatabase(2);
|
||||
JedisPoolConfig config = new JedisPoolConfig();
|
||||
config.setMaxWait(3000l);
|
||||
connectionFactory.setPoolConfig(config);
|
||||
connectionFactory.afterPropertiesSet();
|
||||
public SubscriptionConnectionTests(RedisConnectionFactory connectionFactory) {
|
||||
this.connectionFactory = connectionFactory;
|
||||
ConnectionFactoryTracker.add(connectionFactory);
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -74,7 +74,45 @@ public class SubscriptionConnectionTests {
|
||||
container.destroy();
|
||||
}
|
||||
}
|
||||
connectionFactory.destroy();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void cleanUp() {
|
||||
ConnectionFactoryTracker.cleanUp();
|
||||
}
|
||||
|
||||
@Parameters
|
||||
public static Collection<Object[]> testParams() {
|
||||
// Jedis
|
||||
JedisConnectionFactory jedisConnFactory = new JedisConnectionFactory();
|
||||
jedisConnFactory.setPort(SettingsUtils.getPort());
|
||||
jedisConnFactory.setHostName(SettingsUtils.getHost());
|
||||
jedisConnFactory.setDatabase(2);
|
||||
jedisConnFactory.afterPropertiesSet();
|
||||
|
||||
// Lettuce
|
||||
LettuceConnectionFactory lettuceConnFactory = new LettuceConnectionFactory();
|
||||
lettuceConnFactory.setPort(SettingsUtils.getPort());
|
||||
lettuceConnFactory.setHostName(SettingsUtils.getHost());
|
||||
lettuceConnFactory.setDatabase(2);
|
||||
lettuceConnFactory.setValidateConnection(true);
|
||||
lettuceConnFactory.afterPropertiesSet();
|
||||
|
||||
// SRP
|
||||
SrpConnectionFactory srpConnFactory = new SrpConnectionFactory();
|
||||
srpConnFactory.setPort(SettingsUtils.getPort());
|
||||
srpConnFactory.setHostName(SettingsUtils.getHost());
|
||||
srpConnFactory.afterPropertiesSet();
|
||||
|
||||
// RJC
|
||||
RjcConnectionFactory rjcConnFactory = new RjcConnectionFactory();
|
||||
rjcConnFactory.setPort(SettingsUtils.getPort());
|
||||
rjcConnFactory.setHostName(SettingsUtils.getHost());
|
||||
rjcConnFactory.setDatabase(2);
|
||||
rjcConnFactory.afterPropertiesSet();
|
||||
|
||||
return Arrays.asList(new Object[][] { { jedisConnFactory }, { lettuceConnFactory },
|
||||
{ srpConnFactory }, { rjcConnFactory } });
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -110,8 +148,7 @@ public class SubscriptionConnectionTests {
|
||||
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
|
||||
container.setConnectionFactory(connectionFactory);
|
||||
container.setBeanName("container" + i);
|
||||
container.addMessageListener(listener,
|
||||
Arrays.asList(new ChannelTopic(CHANNEL)));
|
||||
container.addMessageListener(listener, Arrays.asList(new ChannelTopic(CHANNEL)));
|
||||
container.setTaskExecutor(new SyncTaskExecutor());
|
||||
container.setSubscriptionExecutor(new SimpleAsyncTaskExecutor());
|
||||
container.afterPropertiesSet();
|
||||
@@ -140,8 +177,7 @@ public class SubscriptionConnectionTests {
|
||||
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
|
||||
container.setConnectionFactory(connectionFactory);
|
||||
container.setBeanName("container" + i);
|
||||
container.addMessageListener(listener,
|
||||
Arrays.asList(new ChannelTopic(CHANNEL)));
|
||||
container.addMessageListener(listener, Arrays.asList(new ChannelTopic(CHANNEL)));
|
||||
container.setTaskExecutor(new SyncTaskExecutor());
|
||||
container.setSubscriptionExecutor(new SimpleAsyncTaskExecutor());
|
||||
container.afterPropertiesSet();
|
||||
@@ -154,8 +190,7 @@ public class SubscriptionConnectionTests {
|
||||
Thread.sleep(100);
|
||||
|
||||
// Unsubscribe all listeners from all topics, freeing up a connection
|
||||
containers.get(0).removeMessageListener(null,
|
||||
Arrays.asList(new Topic[] {}));
|
||||
containers.get(0).removeMessageListener(null, Arrays.asList(new Topic[] {}));
|
||||
|
||||
// verify we can now get a connection from the pool
|
||||
RedisConnection connection = connectionFactory.getConnection();
|
||||
|
||||
Reference in New Issue
Block a user