package com.lambdaworks.redis.masterslave;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import java.util.Arrays;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;
import com.lambdaworks.redis.RedisClient;
import com.lambdaworks.redis.RedisURI;
import com.lambdaworks.redis.codec.Utf8StringCodec;
import com.lambdaworks.redis.pubsub.RedisPubSubAdapter;
import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnection;
import com.lambdaworks.redis.pubsub.api.async.RedisPubSubAsyncCommands;
import com.lambdaworks.redis.resource.ClientResources;
import io.netty.util.concurrent.EventExecutorGroup;
/**
* @author Mark Paluch
*/
@RunWith(MockitoJUnitRunner.class)
public class SentinelTopologyRefreshTest {
@Mock
private RedisClient redisClient;
@Mock
private StatefulRedisPubSubConnection<String, String> connection;
@Mock
private RedisPubSubAsyncCommands<String, String> pubSubAsyncCommands;
@Mock
private ClientResources clientResources;
@Mock
private EventExecutorGroup eventExecutors;
@Mock
private Runnable refreshRunnable;
private SentinelTopologyRefresh sut;
@Before
public void before() throws Exception {
sut = new SentinelTopologyRefresh(redisClient, "mymaster", Arrays.asList(RedisURI.create("localhost", 1234)));
when(redisClient.connectPubSub(any(Utf8StringCodec.class), any())).thenReturn(connection);
when(clientResources.eventExecutorGroup()).thenReturn(eventExecutors);
when(redisClient.getResources()).thenReturn(clientResources);
when(connection.async()).thenReturn(pubSubAsyncCommands);
}
@Test
public void bind() throws Exception {
sut.bind(refreshRunnable);
verify(redisClient).connectPubSub(any(), any());
verify(pubSubAsyncCommands).psubscribe("*");
}
@Test
public void close() throws Exception {
sut.bind(refreshRunnable);
sut.close();
verify(connection).removeListener(any());
verify(connection).close();
}
@Test
public void shouldNotProcessOtherEvents() throws Exception {
RedisPubSubAdapter<String, String> adapter = getAdapter();
adapter.message("*", "*", "irreleval");
verify(eventExecutors).isShuttingDown();
verifyNoMoreInteractions(eventExecutors);
}
@Test
public void shouldProcessElectedLeader() throws Exception {
RedisPubSubAdapter<String, String> adapter = getAdapter();
adapter.message("*", "+elected-leader", "master mymaster 127.0.0.1");
verify(eventExecutors).schedule(any(Runnable.class), anyLong(), any());
}
@Test
public void shouldProcessSwitchMaster() throws Exception {
RedisPubSubAdapter<String, String> adapter = getAdapter();
adapter.message("*", "+switch-master", "mymaster 127.0.0.1");
verify(eventExecutors).schedule(any(Runnable.class), anyLong(), any());
}
@Test
public void shouldProcessFixSlaveConfig() throws Exception {
RedisPubSubAdapter<String, String> adapter = getAdapter();
adapter.message("*", "fix-slave-config", "@ mymaster 127.0.0.1");
verify(eventExecutors).schedule(any(Runnable.class), anyLong(), any());
}
@Test
public void shouldProcessFailoverEnd() throws Exception {
RedisPubSubAdapter<String, String> adapter = getAdapter();
adapter.message("*", "failover-end", "");
verify(eventExecutors).schedule(any(Runnable.class), anyLong(), any());
}
@Test
public void shouldProcessFailoverTimeout() throws Exception {
RedisPubSubAdapter<String, String> adapter = getAdapter();
adapter.message("*", "failover-end-for-timeout", "");
verify(eventExecutors).schedule(any(Runnable.class), anyLong(), any());
}
@Test
public void shouldExecuteOnceWithinATimeout() throws Exception {
RedisPubSubAdapter<String, String> adapter = getAdapter();
adapter.message("*", "failover-end-for-timeout", "");
adapter.message("*", "failover-end-for-timeout", "");
verify(eventExecutors, times(1)).schedule(any(Runnable.class), anyLong(), any());
}
@Test
public void shouldNotProcessIfExecutorIsShuttingDown() throws Exception {
RedisPubSubAdapter<String, String> adapter = getAdapter();
when(eventExecutors.isShuttingDown()).thenReturn(true);
adapter.message("*", "failover-end-for-timeout", "");
verify(eventExecutors, never()).schedule(any(Runnable.class), anyLong(), any());
}
private RedisPubSubAdapter<String, String> getAdapter() {
sut.bind(refreshRunnable);
return (RedisPubSubAdapter<String, String>) ReflectionTestUtils.getField(sut,
"adapter");
}
}