/*
* Copyright 2015-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.core;
import static org.hamcrest.core.Is.*;
import static org.hamcrest.core.IsCollectionContaining.*;
import static org.hamcrest.core.IsNull.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisClusterCommands.AddSlots;
import org.springframework.data.redis.connection.RedisClusterConnection;
import org.springframework.data.redis.connection.RedisClusterNode;
import org.springframework.data.redis.connection.RedisClusterNode.SlotRange;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisServerCommands.MigrateOption;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* @author Christoph Strobl
*/
@RunWith(MockitoJUnitRunner.Silent.class)
public class DefaultClusterOperationsUnitTests {
static final RedisClusterNode NODE_1 = RedisClusterNode.newRedisClusterNode().listeningAt("127.0.0.1", 6379)
.withId("d1861060fe6a534d42d8a19aeb36600e18785e04").build();
static final RedisClusterNode NODE_2 = RedisClusterNode.newRedisClusterNode().listeningAt("127.0.0.1", 6380)
.withId("0f2ee5df45d18c50aca07228cc18b1da96fd5e84").build();
@Mock RedisConnectionFactory connectionFactory;
@Mock RedisClusterConnection connection;
RedisSerializer<String> serializer;
DefaultClusterOperations<String, String> clusterOps;
@Before
public void setUp() {
when(connectionFactory.getConnection()).thenReturn(connection);
when(connectionFactory.getClusterConnection()).thenReturn(connection);
serializer = new StringRedisSerializer();
RedisTemplate<String, String> template = new RedisTemplate<String, String>();
template.setConnectionFactory(connectionFactory);
template.setValueSerializer(serializer);
template.setKeySerializer(serializer);
template.afterPropertiesSet();
this.clusterOps = new DefaultClusterOperations<String, String>(template);
}
@Test // DATAREDIS-315
public void keysShouldDelegateToConnectionCorrectly() {
Set<byte[]> keys = new HashSet<byte[]>(Arrays.asList(serializer.serialize("key-1"), serializer.serialize("key-2")));
when(connection.keys(any(RedisClusterNode.class), any(byte[].class))).thenReturn(keys);
assertThat(clusterOps.keys(NODE_1, "*"), hasItems("key-1", "key-2"));
}
@Test(expected = IllegalArgumentException.class) // DATAREDIS-315
public void keysShouldThrowExceptionWhenNodeIsNull() {
clusterOps.keys(null, "*");
}
@Test // DATAREDIS-315
public void keysShouldReturnEmptySetWhenNoKeysAvailable() {
when(connection.keys(any(RedisClusterNode.class), any(byte[].class))).thenReturn(null);
assertThat(clusterOps.keys(NODE_1, "*"), notNullValue());
}
@Test // DATAREDIS-315
public void randomKeyShouldDelegateToConnection() {
when(connection.randomKey(any(RedisClusterNode.class))).thenReturn(serializer.serialize("key-1"));
assertThat(clusterOps.randomKey(NODE_1), is("key-1"));
}
@Test(expected = IllegalArgumentException.class) // DATAREDIS-315
public void randomKeyShouldThrowExceptionWhenNodeIsNull() {
clusterOps.randomKey(null);
}
@Test // DATAREDIS-315
public void randomKeyShouldReturnNullWhenNoKeyAvailable() {
when(connection.randomKey(any(RedisClusterNode.class))).thenReturn(null);
assertThat(clusterOps.randomKey(NODE_1), nullValue());
}
@Test // DATAREDIS-315
public void pingShouldDelegateToConnection() {
when(connection.ping(any(RedisClusterNode.class))).thenReturn("PONG");
assertThat(clusterOps.ping(NODE_1), is("PONG"));
}
@Test(expected = IllegalArgumentException.class) // DATAREDIS-315
public void pingShouldThrowExceptionWhenNodeIsNull() {
clusterOps.ping(null);
}
@Test // DATAREDIS-315
public void addSlotsShouldDelegateToConnection() {
clusterOps.addSlots(NODE_1, 1, 2, 3);
verify(connection, times(1)).clusterAddSlots(eq(NODE_1), Mockito.<int[]> any());
}
@Test(expected = IllegalArgumentException.class) // DATAREDIS-315
public void addSlotsShouldThrowExceptionWhenNodeIsNull() {
clusterOps.addSlots(null);
}
@Test // DATAREDIS-315
public void addSlotsWithRangeShouldDelegateToConnection() {
clusterOps.addSlots(NODE_1, new SlotRange(1, 3));
verify(connection, times(1)).clusterAddSlots(eq(NODE_1), Mockito.<int[]> any());
}
@Test(expected = IllegalArgumentException.class) // DATAREDIS-315
public void addSlotsWithRangeShouldThrowExceptionWhenRangeIsNull() {
clusterOps.addSlots(NODE_1, (SlotRange) null);
}
@Test // DATAREDIS-315
public void bgSaveShouldDelegateToConnection() {
clusterOps.bgSave(NODE_1);
verify(connection, times(1)).bgSave(eq(NODE_1));
}
@Test(expected = IllegalArgumentException.class) // DATAREDIS-315
public void bgSaveShouldThrowExceptionWhenNodeIsNull() {
clusterOps.bgSave(null);
}
@Test // DATAREDIS-315
public void meetShouldDelegateToConnection() {
clusterOps.meet(NODE_1);
verify(connection, times(1)).clusterMeet(eq(NODE_1));
}
@Test(expected = IllegalArgumentException.class) // DATAREDIS-315
public void meetShouldThrowExceptionWhenNodeIsNull() {
clusterOps.meet(null);
}
@Test // DATAREDIS-315
public void forgetShouldDelegateToConnection() {
clusterOps.forget(NODE_1);
verify(connection, times(1)).clusterForget(eq(NODE_1));
}
@Test(expected = IllegalArgumentException.class) // DATAREDIS-315
public void forgetShouldThrowExceptionWhenNodeIsNull() {
clusterOps.forget(null);
}
@Test // DATAREDIS-315
public void flushDbShouldDelegateToConnection() {
clusterOps.flushDb(NODE_1);
verify(connection, times(1)).flushDb(eq(NODE_1));
}
@Test(expected = IllegalArgumentException.class) // DATAREDIS-315
public void flushDbShouldThrowExceptionWhenNodeIsNull() {
clusterOps.flushDb(null);
}
@Test // DATAREDIS-315
public void getSlavesShouldDelegateToConnection() {
clusterOps.getSlaves(NODE_1);
verify(connection, times(1)).clusterGetSlaves(eq(NODE_1));
}
@Test(expected = IllegalArgumentException.class) // DATAREDIS-315
public void getSlavesShouldThrowExceptionWhenNodeIsNull() {
clusterOps.getSlaves(null);
}
@Test // DATAREDIS-315
public void saveShouldDelegateToConnection() {
clusterOps.save(NODE_1);
verify(connection, times(1)).save(eq(NODE_1));
}
@Test(expected = IllegalArgumentException.class) // DATAREDIS-315
public void saveShouldThrowExceptionWhenNodeIsNull() {
clusterOps.save(null);
}
@Test // DATAREDIS-315
public void shutdownShouldDelegateToConnection() {
clusterOps.shutdown(NODE_1);
verify(connection, times(1)).shutdown(eq(NODE_1));
}
@Test(expected = IllegalArgumentException.class) // DATAREDIS-315
public void shutdownShouldThrowExceptionWhenNodeIsNull() {
clusterOps.shutdown(null);
}
@Test // DATAREDIS-315
public void executeShouldDelegateToConnection() {
final byte[] key = serializer.serialize("foo");
clusterOps.execute(new RedisClusterCallback<String>() {
@Override
public String doInRedis(RedisClusterConnection connection) throws DataAccessException {
return serializer.deserialize(connection.get(key));
}
});
verify(connection, times(1)).get(eq(key));
}
@Test(expected = IllegalArgumentException.class) // DATAREDIS-315
public void executeShouldThrowExceptionWhenCallbackIsNull() {
clusterOps.execute(null);
}
@Test // DATAREDIS-315
public void reshardShouldExecuteCommandsCorrectly() {
byte[] key = "foo".getBytes();
when(connection.clusterGetKeysInSlot(eq(100), anyInt())).thenReturn(Collections.singletonList(key));
clusterOps.reshard(NODE_1, 100, NODE_2);
verify(connection, times(1)).clusterSetSlot(eq(NODE_2), eq(100), eq(AddSlots.IMPORTING));
verify(connection, times(1)).clusterSetSlot(eq(NODE_1), eq(100), eq(AddSlots.MIGRATING));
verify(connection, times(1)).clusterGetKeysInSlot(eq(100), anyInt());
verify(connection, times(1)).migrate(any(byte[].class), eq(NODE_1), eq(0), eq(MigrateOption.COPY));
verify(connection, times(1)).clusterSetSlot(eq(NODE_2), eq(100), eq(AddSlots.NODE));
}
}