/* * Copyright 2011-2017 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.listener; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import static org.junit.Assume.*; import java.util.Arrays; import java.util.Collection; import java.util.LinkedHashSet; import java.util.Set; import java.util.concurrent.BlockingDeque; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; 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.ObjectFactory; import org.springframework.data.redis.RedisTestProfileValueSource; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.listener.adapter.MessageListenerAdapter; import org.springframework.data.redis.test.util.RedisSentinelRule; /** * Base test class for PubSub integration tests * * @author Costin Leau * @author Jennifer Hickey */ @RunWith(Parameterized.class) public class PubSubTests<T> { public @Rule RedisSentinelRule sentinelRule = RedisSentinelRule.withDefaultConfig().sentinelsDisabled(); private static final String CHANNEL = "pubsub::test"; protected RedisMessageListenerContainer container; protected ObjectFactory<T> factory; @SuppressWarnings("rawtypes") protected RedisTemplate template; private final BlockingDeque<Object> bag = new LinkedBlockingDeque<Object>(99); private final Object handler = new Object() { @SuppressWarnings("unused") public void handleMessage(Object message) { bag.add(message); } }; private final MessageListenerAdapter adapter = new MessageListenerAdapter(handler); @BeforeClass public static void shouldRun() { assumeTrue(RedisTestProfileValueSource.matches("runLongTests", "true")); } @Before public void setUp() throws Exception { bag.clear(); adapter.setSerializer(template.getValueSerializer()); adapter.afterPropertiesSet(); container = new RedisMessageListenerContainer(); container.setConnectionFactory(template.getConnectionFactory()); container.setBeanName("container"); container.addMessageListener(adapter, Arrays.asList(new ChannelTopic(CHANNEL))); container.setTaskExecutor(new SyncTaskExecutor()); container.setSubscriptionExecutor(new SimpleAsyncTaskExecutor()); container.afterPropertiesSet(); container.start(); Thread.sleep(1000); } @After public void tearDown() throws Exception { container.destroy(); } @SuppressWarnings("rawtypes") public PubSubTests(ObjectFactory<T> factory, RedisTemplate template) { this.factory = factory; this.template = template; ConnectionFactoryTracker.add(template.getConnectionFactory()); } @AfterClass public static void cleanUp() { ConnectionFactoryTracker.cleanUp(); } @Parameters public static Collection<Object[]> testParams() { return PubSubTestParams.testParams(); } /** * Return a new instance of T * * @return */ protected T getT() { return factory.instance(); } @SuppressWarnings("unchecked") @Test public void testContainerSubscribe() throws Exception { T payload1 = getT(); T payload2 = getT(); template.convertAndSend(CHANNEL, payload1); template.convertAndSend(CHANNEL, payload2); Set<T> set = new LinkedHashSet<T>(); set.add((T) bag.poll(1, TimeUnit.SECONDS)); set.add((T) bag.poll(1, TimeUnit.SECONDS)); assertThat(set, hasItems(payload1, payload2)); } @Test public void testMessageBatch() throws Exception { int COUNT = 10; for (int i = 0; i < COUNT; i++) { template.convertAndSend(CHANNEL, getT()); } Thread.sleep(1000); assertEquals(COUNT, bag.size()); } @Test public void testContainerUnsubscribe() throws Exception { T payload1 = getT(); T payload2 = getT(); container.removeMessageListener(adapter, new ChannelTopic(CHANNEL)); template.convertAndSend(CHANNEL, payload1); template.convertAndSend(CHANNEL, payload2); assertNull(bag.poll(1, TimeUnit.SECONDS)); } @Test public void testStartNoListeners() { container.removeMessageListener(adapter, new ChannelTopic(CHANNEL)); container.stop(); // DATREDIS-207 This test previously took 5 seconds on start due to monitor wait container.start(); } @SuppressWarnings("unchecked") @Test // DATAREDIS-251 public void testStartListenersToNoSpecificChannelTest() throws InterruptedException { container.removeMessageListener(adapter, new ChannelTopic(CHANNEL)); container.addMessageListener(adapter, Arrays.asList(new PatternTopic("*"))); container.start(); Thread.sleep(1000); // give the container a little time to recover T payload = getT(); template.convertAndSend(CHANNEL, payload); Set<T> set = new LinkedHashSet<T>(); set.add((T) bag.poll(3, TimeUnit.SECONDS)); assertThat(set, hasItems(payload)); } }