/* * Copyright 2014-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.connection.jedis; import static org.hamcrest.core.IsEqual.*; import static org.junit.Assert.*; import static org.mockito.Mockito.*; import java.io.IOException; import java.util.Collections; import java.util.Map.Entry; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; import org.mockito.ArgumentCaptor; import org.springframework.dao.InvalidDataAccessResourceUsageException; import org.springframework.data.redis.connection.AbstractConnectionUnitTestBase; import org.springframework.data.redis.connection.RedisServerCommands.ShutdownOption; import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; import org.springframework.data.redis.connection.jedis.JedisConnectionUnitTestSuite.JedisConnectionPipelineUnitTests; import org.springframework.data.redis.connection.jedis.JedisConnectionUnitTestSuite.JedisConnectionUnitTests; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.ScanOptions; import redis.clients.jedis.Client; import redis.clients.jedis.Jedis; import redis.clients.jedis.ScanParams; import redis.clients.jedis.ScanResult; /** * @author Christoph Strobl */ @RunWith(Suite.class) @SuiteClasses({ JedisConnectionUnitTests.class, JedisConnectionPipelineUnitTests.class }) public class JedisConnectionUnitTestSuite { public static class JedisConnectionUnitTests extends AbstractConnectionUnitTestBase<Client> { protected JedisConnection connection; private Jedis jedisSpy; @Before public void setUp() { jedisSpy = spy(new MockedClientJedis("http://localhost:1234", getNativeRedisConnectionMock())); connection = new JedisConnection(jedisSpy); } @Test // DATAREDIS-184 public void shutdownWithNullShouldDelegateCommandCorrectly() { connection.shutdown(null); verifyNativeConnectionInvocation().shutdown(); } @Test // DATAREDIS-184 public void shutdownNosaveShouldBeSentCorrectlyUsingLuaScript() { connection.shutdown(ShutdownOption.NOSAVE); ArgumentCaptor<byte[]> captor = ArgumentCaptor.forClass(byte[].class); verifyNativeConnectionInvocation().eval(captor.capture(), any(byte[].class), any(byte[][].class)); assertThat(captor.getValue(), equalTo("return redis.call('SHUTDOWN','NOSAVE')".getBytes())); } @Test // DATAREDIS-184 public void shutdownSaveShouldBeSentCorrectlyUsingLuaScript() { connection.shutdown(ShutdownOption.SAVE); ArgumentCaptor<byte[]> captor = ArgumentCaptor.forClass(byte[].class); verifyNativeConnectionInvocation().eval(captor.capture(), any(byte[].class), any(byte[][].class)); assertThat(captor.getValue(), equalTo("return redis.call('SHUTDOWN','SAVE')".getBytes())); } @Test // DATAREDIS-267 public void killClientShouldDelegateCallCorrectly() { connection.killClient("127.0.0.1", 1001); verifyNativeConnectionInvocation().clientKill(eq("127.0.0.1:1001")); } @Test // DATAREDIS-270 public void getClientNameShouldSendRequestCorrectly() { connection.getClientName(); verifyNativeConnectionInvocation().clientGetname(); } @Test(expected = IllegalArgumentException.class) // DATAREDIS-277 public void slaveOfShouldThrowExectpionWhenCalledForNullHost() { connection.slaveOf(null, 0); } @Test // DATAREDIS-277 public void slaveOfShouldBeSentCorrectly() { connection.slaveOf("127.0.0.1", 1001); verifyNativeConnectionInvocation().slaveof(eq("127.0.0.1"), eq(1001)); } @Test // DATAREDIS-277 public void slaveOfNoOneShouldBeSentCorrectly() { connection.slaveOfNoOne(); verifyNativeConnectionInvocation().slaveofNoOne(); } @Test(expected = InvalidDataAccessResourceUsageException.class) // DATAREDIS-330 public void shouldThrowExceptionWhenAccessingRedisSentinelsCommandsWhenNoSentinelsConfigured() { connection.getSentinelConnection(); } @Test(expected = IllegalArgumentException.class) // DATAREDIS-472 public void restoreShouldThrowExceptionWhenTtlInMillisExceedsIntegerRange() { connection.restore("foo".getBytes(), new Long(Integer.MAX_VALUE) + 1L, "bar".getBytes()); } @Test(expected = IllegalArgumentException.class) // DATAREDIS-472 public void setExShouldThrowExceptionWhenTimeExceedsIntegerRange() { connection.setEx("foo".getBytes(), new Long(Integer.MAX_VALUE) + 1L, "bar".getBytes()); } @Test(expected = IllegalArgumentException.class) // DATAREDIS-472 public void getRangeShouldThrowExceptionWhenStartExceedsIntegerRange() { connection.getRange("foo".getBytes(), new Long(Integer.MAX_VALUE) + 1L, Integer.MAX_VALUE); } @Test(expected = IllegalArgumentException.class) // DATAREDIS-472 public void getRangeShouldThrowExceptionWhenEndExceedsIntegerRange() { connection.getRange("foo".getBytes(), Integer.MAX_VALUE, new Long(Integer.MAX_VALUE) + 1L); } @Test(expected = IllegalArgumentException.class) // DATAREDIS-472 public void sRandMemberShouldThrowExceptionWhenCountExceedsIntegerRange() { connection.sRandMember("foo".getBytes(), new Long(Integer.MAX_VALUE) + 1L); } @Test(expected = IllegalArgumentException.class) // DATAREDIS-472 public void zRangeByScoreShouldThrowExceptionWhenOffsetExceedsIntegerRange() { connection.zRangeByScore("foo".getBytes(), "foo", "bar", new Long(Integer.MAX_VALUE) + 1L, Integer.MAX_VALUE); } @Test(expected = IllegalArgumentException.class) // DATAREDIS-472 public void zRangeByScoreShouldThrowExceptionWhenCountExceedsIntegerRange() { connection.zRangeByScore("foo".getBytes(), "foo", "bar", Integer.MAX_VALUE, new Long(Integer.MAX_VALUE) + 1L); } @Test // DATAREDIS-531 public void scanShouldKeepTheConnectionOpen() { doReturn(new ScanResult<String>("0", Collections.<String> emptyList())).when(jedisSpy).scan(anyString(), any(ScanParams.class)); connection.scan(ScanOptions.NONE); verify(jedisSpy, never()).quit(); } @Test // DATAREDIS-531 public void scanShouldCloseTheConnectionWhenCursorIsClosed() throws IOException { doReturn(new ScanResult<String>("0", Collections.<String> emptyList())).when(jedisSpy).scan(anyString(), any(ScanParams.class)); Cursor<byte[]> cursor = connection.scan(ScanOptions.NONE); cursor.close(); verify(jedisSpy, times(1)).quit(); } @Test // DATAREDIS-531 public void sScanShouldKeepTheConnectionOpen() { doReturn(new ScanResult<String>("0", Collections.<String> emptyList())).when(jedisSpy).sscan(any(byte[].class), any(byte[].class), any(ScanParams.class)); connection.sScan("foo".getBytes(), ScanOptions.NONE); verify(jedisSpy, never()).quit(); } @Test // DATAREDIS-531 public void sScanShouldCloseTheConnectionWhenCursorIsClosed() throws IOException { doReturn(new ScanResult<String>("0", Collections.<String> emptyList())).when(jedisSpy).sscan(any(byte[].class), any(byte[].class), any(ScanParams.class)); Cursor<byte[]> cursor = connection.sScan("foo".getBytes(), ScanOptions.NONE); cursor.close(); verify(jedisSpy, times(1)).quit(); } @Test // DATAREDIS-531 public void zScanShouldKeepTheConnectionOpen() { doReturn(new ScanResult<String>("0", Collections.<String> emptyList())).when(jedisSpy).zscan(any(byte[].class), any(byte[].class), any(ScanParams.class)); connection.zScan("foo".getBytes(), ScanOptions.NONE); verify(jedisSpy, never()).quit(); } @Test // DATAREDIS-531 public void zScanShouldCloseTheConnectionWhenCursorIsClosed() throws IOException { doReturn(new ScanResult<String>("0", Collections.<String> emptyList())).when(jedisSpy).zscan(any(byte[].class), any(byte[].class), any(ScanParams.class)); Cursor<Tuple> cursor = connection.zScan("foo".getBytes(), ScanOptions.NONE); cursor.close(); verify(jedisSpy, times(1)).quit(); } @Test // DATAREDIS-531 public void hScanShouldKeepTheConnectionOpen() { doReturn(new ScanResult<String>("0", Collections.<String> emptyList())).when(jedisSpy).hscan(any(byte[].class), any(byte[].class), any(ScanParams.class)); connection.hScan("foo".getBytes(), ScanOptions.NONE); verify(jedisSpy, never()).quit(); } @Test // DATAREDIS-531 public void hScanShouldCloseTheConnectionWhenCursorIsClosed() throws IOException { doReturn(new ScanResult<String>("0", Collections.<String> emptyList())).when(jedisSpy).hscan(any(byte[].class), any(byte[].class), any(ScanParams.class)); Cursor<Entry<byte[], byte[]>> cursor = connection.hScan("foo".getBytes(), ScanOptions.NONE); cursor.close(); verify(jedisSpy, times(1)).quit(); } } public static class JedisConnectionPipelineUnitTests extends JedisConnectionUnitTests { @Before public void setUp() { super.setUp(); connection.openPipeline(); } @Override @Test(expected = UnsupportedOperationException.class) // DATAREDIS-184 public void shutdownNosaveShouldBeSentCorrectlyUsingLuaScript() { super.shutdownNosaveShouldBeSentCorrectlyUsingLuaScript(); } @Override @Test(expected = UnsupportedOperationException.class) // DATAREDIS-184 public void shutdownSaveShouldBeSentCorrectlyUsingLuaScript() { super.shutdownSaveShouldBeSentCorrectlyUsingLuaScript(); } @Test(expected = UnsupportedOperationException.class) // DATAREDIS-267 public void killClientShouldDelegateCallCorrectly() { super.killClientShouldDelegateCallCorrectly(); } @Override @Test(expected = UnsupportedOperationException.class) // DATAREDIS-270 public void getClientNameShouldSendRequestCorrectly() { super.getClientNameShouldSendRequestCorrectly(); } @Override @Test(expected = UnsupportedOperationException.class) // DATAREDIS-277 public void slaveOfShouldBeSentCorrectly() { super.slaveOfShouldBeSentCorrectly(); } @Test(expected = UnsupportedOperationException.class) // DATAREDIS-277 public void slaveOfNoOneShouldBeSentCorrectly() { super.slaveOfNoOneShouldBeSentCorrectly(); } @Test(expected = UnsupportedOperationException.class) // DATAREDIS-531 public void scanShouldKeepTheConnectionOpen() { super.scanShouldKeepTheConnectionOpen(); } @Test(expected = UnsupportedOperationException.class) // DATAREDIS-531 public void scanShouldCloseTheConnectionWhenCursorIsClosed() throws IOException { super.scanShouldCloseTheConnectionWhenCursorIsClosed(); } @Test(expected = UnsupportedOperationException.class) // DATAREDIS-531 public void sScanShouldKeepTheConnectionOpen() { super.sScanShouldKeepTheConnectionOpen(); } @Test(expected = UnsupportedOperationException.class) // DATAREDIS-531 public void sScanShouldCloseTheConnectionWhenCursorIsClosed() throws IOException { super.sScanShouldCloseTheConnectionWhenCursorIsClosed(); } @Test(expected = UnsupportedOperationException.class) // DATAREDIS-531 public void zScanShouldKeepTheConnectionOpen() { super.zScanShouldKeepTheConnectionOpen(); } @Test(expected = UnsupportedOperationException.class) // DATAREDIS-531 public void zScanShouldCloseTheConnectionWhenCursorIsClosed() throws IOException { super.zScanShouldCloseTheConnectionWhenCursorIsClosed(); } @Test(expected = UnsupportedOperationException.class) // DATAREDIS-531 public void hScanShouldKeepTheConnectionOpen() { super.hScanShouldKeepTheConnectionOpen(); } @Test(expected = UnsupportedOperationException.class) // DATAREDIS-531 public void hScanShouldCloseTheConnectionWhenCursorIsClosed() throws IOException { super.hScanShouldCloseTheConnectionWhenCursorIsClosed(); } } /** * {@link Jedis} extension allowing to use mocked object as {@link Client}. */ private static class MockedClientJedis extends Jedis { public MockedClientJedis(String host, Client client) { super(host); this.client = client; } } }