DATAREDIS-268 - Add support for 'CLIENT LIST'.

'RedisConnection' and 'RedisTemplate' have been extended by 'getClientList' retrieving client informations from redis. 'RedisClientInfo' provides access via specified getters as well as an more general approach directly using the keys (like 'qubuf').

The operation is available for 'jedis', 'lettuce' and 'srp'.

Original Pull Request: #53
This commit is contained in:
Christoph Strobl
2014-03-24 09:05:33 +01:00
committed by Thomas Darimont
parent 4bf438f563
commit 2679405e96
28 changed files with 937 additions and 17 deletions

View File

@@ -15,8 +15,7 @@
*/
package org.springframework.data.redis.connection;
import static org.hamcrest.core.IsEqual.*;
import static org.hamcrest.core.IsNull.*;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.junit.Assume.*;
import static org.springframework.data.redis.SpinBarrier.*;
@@ -38,6 +37,7 @@ import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.hamcrest.core.IsNot;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -54,6 +54,7 @@ import org.springframework.data.redis.connection.RedisZSetCommands.Tuple;
import org.springframework.data.redis.connection.SortParameters.Order;
import org.springframework.data.redis.connection.StringRedisConnection.StringTuple;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.types.RedisClientInfo;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@@ -1892,6 +1893,25 @@ public abstract class AbstractConnectionIntegrationTests {
connection.setClientName("foo".getBytes());
}
/**
* @see DATAREDIS-268
*/
@Test
public void testListClientsContainsAtLeastOneElement() {
actual.add(connection.getClientList());
List<Object> results = getResults();
assertNotNull(results.get(0));
List<?> firstEntry = (List<?>) results.get(0);
assertThat(firstEntry.size(), IsNot.not(0));
assertThat(firstEntry.get(0), is(instanceOf(RedisClientInfo.class)));
RedisClientInfo info = (RedisClientInfo) firstEntry.get(0);
assertThat(info.getDatabaseId(), is(notNullValue()));
}
protected void verifyResults(List<Object> expected) {
assertEquals(expected, getResults());
}

View File

@@ -254,4 +254,13 @@ public class JedisConnectionPipelineIntegrationTests extends AbstractConnectionP
public void clientSetNameWorksCorrectly() {
super.clientSetNameWorksCorrectly();
}
/**
* @see DATAREDIS-268
*/
@Override
@Test(expected = UnsupportedOperationException.class)
public void testListClientsContainsAtLeastOneElement() {
super.testListClientsContainsAtLeastOneElement();
}
}

View File

@@ -1,7 +1,21 @@
/*
* Copyright 2013-2014 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.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.*;
import java.util.List;
@@ -10,6 +24,10 @@ import org.junit.Test;
import org.springframework.data.redis.connection.RedisPipelineException;
import org.springframework.test.annotation.IfProfileValue;
/**
* @author Jennifer Hickey
* @author Christoph Strobl
*/
public class JedisConnectionPipelineTxIntegrationTests extends JedisConnectionTransactionIntegrationTests {
@Ignore("Jedis issue: Pipeline tries to return String instead of List<String>")
@@ -50,4 +68,13 @@ public class JedisConnectionPipelineTxIntegrationTests extends JedisConnectionTr
// Return exec results and this test should behave exactly like its superclass
return txResults;
}
/**
* @see DATAREDIS-268
*/
@Override
@Test(expected = UnsupportedOperationException.class)
public void testListClientsContainsAtLeastOneElement() {
super.testListClientsContainsAtLeastOneElement();
}
}

View File

@@ -200,4 +200,12 @@ public class JedisConnectionTransactionIntegrationTests extends AbstractConnecti
super.clientSetNameWorksCorrectly();
}
/**
* @see DATAREDIS-268
*/
@Override
@Test(expected = UnsupportedOperationException.class)
public void testListClientsContainsAtLeastOneElement() {
super.testListClientsContainsAtLeastOneElement();
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2014 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 java.util.Collections;
import org.junit.Test;
import org.springframework.data.redis.core.types.RedisClientInfo;
/**
* @author Christoph Strobl
*/
public class JedisConvertersUnitTests {
private static final String CLIENT_ALL_SINGLE_LINE_RESPONSE = "addr=127.0.0.1:60311 fd=6 name= age=4059 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=client";
/**
* @see DATAREDIS-268
*/
@Test
public void convertingEmptyStringToListOfRedisClientInfoShouldReturnEmptyList() {
assertThat(JedisConverters.toListOfRedisClientInformation(""), equalTo(Collections.<RedisClientInfo> emptyList()));
}
/**
* @see DATAREDIS-268
*/
@Test
public void convertingNullToListOfRedisClientInfoShouldReturnEmptyList() {
assertThat(JedisConverters.toListOfRedisClientInformation(null), equalTo(Collections.<RedisClientInfo> emptyList()));
}
/**
* @see DATAREDIS-268
*/
@Test
public void convertingMultipleLiesToListOfRedisClientInfoReturnsListCorrectly() {
StringBuilder sb = new StringBuilder();
sb.append(CLIENT_ALL_SINGLE_LINE_RESPONSE);
sb.append("\r\n");
sb.append(CLIENT_ALL_SINGLE_LINE_RESPONSE);
assertThat(JedisConverters.toListOfRedisClientInformation(sb.toString()).size(), equalTo(2));
}
}

View File

@@ -818,4 +818,13 @@ public class JRedisConnectionIntegrationTests extends AbstractConnectionIntegrat
public void clientSetNameWorksCorrectly() {
super.clientSetNameWorksCorrectly();
}
/**
* @see DATAREDIS-268
*/
@Override
@Test(expected = UnsupportedOperationException.class)
public void testListClientsContainsAtLeastOneElement() {
super.testListClientsContainsAtLeastOneElement();
}
}

View File

@@ -113,4 +113,13 @@ public class LettuceConnectionPipelineIntegrationTests extends AbstractConnectio
}
}
/**
* @see DATAREDIS-268
*/
@Override
@Test(expected = UnsupportedOperationException.class)
public void testListClientsContainsAtLeastOneElement() {
super.testListClientsContainsAtLeastOneElement();
}
}

View File

@@ -83,4 +83,13 @@ public class LettuceConnectionPipelineTxIntegrationTests extends LettuceConnecti
return txResults;
}
/**
* @see DATAREDIS-268
*/
@Override
@Test(expected = UnsupportedOperationException.class)
public void testListClientsContainsAtLeastOneElement() {
super.testListClientsContainsAtLeastOneElement();
}
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright 2014 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.hamcrest.core.IsEqual.*;
import static org.junit.Assert.*;
import java.util.Collections;
import org.junit.Test;
import org.springframework.data.redis.core.types.RedisClientInfo;
/**
* @author Christoph Strobl
*/
public class LettuceConvertersUnitTests {
private static final String CLIENT_ALL_SINGLE_LINE_RESPONSE = "addr=127.0.0.1:60311 fd=6 name= age=4059 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=client";
/**
* @see DATAREDIS-268
*/
@Test
public void convertingEmptyStringToListOfRedisClientInfoShouldReturnEmptyList() {
assertThat(LettuceConverters.toListOfRedisClientInformation(""), equalTo(Collections.<RedisClientInfo> emptyList()));
}
/**
* @see DATAREDIS-268
*/
@Test
public void convertingNullToListOfRedisClientInfoShouldReturnEmptyList() {
assertThat(LettuceConverters.toListOfRedisClientInformation(null),
equalTo(Collections.<RedisClientInfo> emptyList()));
}
/**
* @see DATAREDIS-268
*/
@Test
public void convertingMultipleLiesToListOfRedisClientInfoReturnsListCorrectly() {
StringBuilder sb = new StringBuilder();
sb.append(CLIENT_ALL_SINGLE_LINE_RESPONSE);
sb.append("\r\n");
sb.append(CLIENT_ALL_SINGLE_LINE_RESPONSE);
assertThat(LettuceConverters.toListOfRedisClientInformation(sb.toString()).size(), equalTo(2));
}
}

View File

@@ -59,4 +59,12 @@ public class SrpConnectionTransactionIntegrationTests extends AbstractConnection
public void testZUnionStoreAggWeights() {
super.testZUnionStoreAggWeights();
}
/**
* @see DATAREDIS-268
*/
@Test(expected = UnsupportedOperationException.class)
public void testListClientsContainsAtLeastOneElement() {
super.testListClientsContainsAtLeastOneElement();
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright 2014 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.hamcrest.core.IsEqual.*;
import static org.junit.Assert.*;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collections;
import org.junit.Test;
import org.springframework.data.redis.core.types.RedisClientInfo;
import redis.reply.BulkReply;
import redis.reply.Reply;
/**
* @author Christoph Strobl
*/
public class SrpConvertersUnitTests {
private static final String CLIENT_ALL_SINGLE_LINE_RESPONSE = "addr=127.0.0.1:60311 fd=6 name= age=4059 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=client";
/**
* @see DATAREDIS-268
*/
@Test
public void convertingNullReplyToListOfRedisClientInfoShouldReturnEmptyList() {
assertThat(SrpConverters.toListOfRedisClientInformation(new BulkReply(null)),
equalTo(Collections.<RedisClientInfo> emptyList()));
}
/**
* @see DATAREDIS-268
*/
@Test
public void convertingEmptyReplyToListOfRedisClientInfoShouldReturnEmptyList() {
assertThat(SrpConverters.toListOfRedisClientInformation(new BulkReply(new byte[0])),
equalTo(Collections.<RedisClientInfo> emptyList()));
}
/**
* @see DATAREDIS-268
*/
@Test
public void convertingNullToListOfRedisClientInfoShouldReturnEmptyList() {
assertThat(SrpConverters.toListOfRedisClientInformation(null), equalTo(Collections.<RedisClientInfo> emptyList()));
}
/**
* @see DATAREDIS-268
*/
@Test
public void convertingMultipleLiesToListOfRedisClientInfoReturnsListCorrectly() {
StringBuilder sb = new StringBuilder();
sb.append(CLIENT_ALL_SINGLE_LINE_RESPONSE);
sb.append("\r\n");
sb.append(CLIENT_ALL_SINGLE_LINE_RESPONSE);
assertThat(SrpConverters.toListOfRedisClientInformation(new BulkReply(sb.toString().getBytes())).size(), equalTo(2));
}
/**
* @see DATAREDIS-268
*/
@Test(expected = IllegalArgumentException.class)
public void expectExcptionWhenProvidingInvalidDataInReply() {
SrpConverters.toListOfRedisClientInformation(new Reply<String>() {
@Override
public String data() {
return "foo";
}
@Override
public void write(OutputStream os) throws IOException {
// just do nothing;
}
});
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013 the original author or authors.
* Copyright 2013-2014 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.
@@ -15,15 +15,10 @@
*/
package org.springframework.data.redis.core;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import static org.springframework.data.redis.SpinBarrier.waitFor;
import static org.springframework.data.redis.matcher.RedisTestMatchers.isEqual;
import static org.junit.Assert.*;
import static org.junit.Assume.*;
import static org.springframework.data.redis.SpinBarrier.*;
import static org.springframework.data.redis.matcher.RedisTestMatchers.*;
import java.util.ArrayList;
import java.util.Arrays;
@@ -38,6 +33,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.hamcrest.core.IsNot;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -67,6 +63,7 @@ import org.springframework.data.redis.serializer.StringRedisSerializer;
* Integration test of {@link RedisTemplate}
*
* @author Jennifer Hickey
* @author Christoph Strobl
*/
@RunWith(Parameterized.class)
public class RedisTemplateTests<K, V> {
@@ -703,6 +700,11 @@ public class RedisTemplateTests<K, V> {
Collections.singletonList(key1)));
}
@Test
public void clientListShouldReturnCorrectly() {
assertThat(redisTemplate.getClientList().size(), IsNot.not(0));
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private byte[] serialize(Object value, RedisSerializer serializer) {
if (serializer == null && value instanceof byte[]) {

View File

@@ -0,0 +1,74 @@
/*
* Copyright 2014 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.types;
import org.hamcrest.core.Is;
import org.hamcrest.core.IsEqual;
import org.hamcrest.core.IsNot;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.redis.core.types.RedisClientInfo.RedisClientInfoBuilder;
/**
* @author Christoph Strobl
*/
public class RedisClientInfoUnitTests {
private final String SOURCE_WITH_PLACEHOLDER = "addr=127.0.0.1:57013#fd=6#name=client-1#age=16#idle=0#flags=N#db=0#sub=0#psub=0#multi=-1#qbuf=0#qbuf-free=32768#obl=0#oll=0#omem=0#events=r#cmd=client";
private final String SINGLE_LINE = SOURCE_WITH_PLACEHOLDER.replace('#', ' ');
private final String[] VALUES = SOURCE_WITH_PLACEHOLDER.split("#");
private RedisClientInfo info;
@Before
public void setUp() {
info = RedisClientInfoBuilder.fromString(SINGLE_LINE);
}
@Test
public void testBuilderShouldReadsInfoCorrectlyFromSingleLineString() {
assertValues(info, VALUES);
}
@Test(expected = IllegalArgumentException.class)
public void testGetRequiresNonNullKey() {
info.get((String) null);
}
@Test(expected = IllegalArgumentException.class)
public void testGetRequiresNonBlankKey() {
info.get("");
}
@Test
public void testGetReturnsNullForPropertiesNotAvailable() {
Assert.assertThat(info.get("foo-bar"), IsEqual.equalTo(null));
}
private void assertValues(RedisClientInfo info, String[] values) {
for (String potentialValue : values) {
if (potentialValue.contains("=")) {
String[] keyValuePair = potentialValue.split("=");
Assert.assertThat(info.get(keyValuePair[0]), Is.is(keyValuePair[1]));
} else {
Assert.assertThat(info.get(potentialValue), IsNot.not(null));
}
}
}
}