diff --git a/docs/src/reference/docbook/appendix/appendix-command-reference.xml b/docs/src/reference/docbook/appendix/appendix-command-reference.xml index 4a1d461118..daf999a8fb 100644 --- a/docs/src/reference/docbook/appendix/appendix-command-reference.xml +++ b/docs/src/reference/docbook/appendix/appendix-command-reference.xml @@ -25,7 +25,7 @@ BRPOPLPUSHX CLIENT KILLX CLIENT GETNAMEX - CLIENT LIST- + CLIENT LISTX CLIENT SETNAMEX CONFIG GETX CONFIG RESETSTATX diff --git a/gradle.properties b/gradle.properties index f09fb8eb53..6acf08a349 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ jredisVersion=06052013 jedisVersion=2.4.1 springVersion=3.2.8.RELEASE log4jVersion=1.2.17 -version=1.3.0.BUILD-SNAPSHOT +version=1.3.0.DATAREDIS-268-SNAPSHOT srpVersion=0.7 jacksonVersion=1.8.8 fasterXmlJacksonVersion=2.2.0 diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java index e8ac41eed5..e779d006a4 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java @@ -32,6 +32,7 @@ import org.springframework.data.redis.connection.convert.ListConverter; import org.springframework.data.redis.connection.convert.MapConverter; import org.springframework.data.redis.connection.convert.SetConverter; +import org.springframework.data.redis.core.types.RedisClientInfo; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.util.Assert; @@ -2191,6 +2192,11 @@ public Long time() { return this.delegate.time(); } + @Override + public List getClientList() { + return this.delegate.getClientList(); + } + /** * Specifies if pipelined and tx results should be deserialized to Strings. If false, results of * {@link #closePipeline()} and {@link #exec()} will be of the type returned by the underlying connection diff --git a/src/main/java/org/springframework/data/redis/connection/RedisServerCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisServerCommands.java index 1268d83757..999d273724 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisServerCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisServerCommands.java @@ -18,6 +18,8 @@ import java.util.List; import java.util.Properties; +import org.springframework.data.redis.core.types.RedisClientInfo; + /** * Server-specific commands supported by Redis. * @@ -186,4 +188,13 @@ public enum ShutdownOption { * @since 1.3 */ String getClientName(); + + /** + * Request information and statistics about connected clients. + * + * @return {@link List} of {@link RedisClientInfo} objects. + * @since 1.3 + * @see http://redis.io/commands/client-list + */ + List getClientList(); } diff --git a/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java index ae3d9684e7..4a25597f1c 100644 --- a/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java @@ -22,6 +22,7 @@ import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.types.RedisClientInfo; import org.springframework.data.redis.serializer.RedisSerializer; /** @@ -301,4 +302,10 @@ public interface StringTuple extends Tuple { * @sice 1.3 */ void setClientName(String name); + + /** + * @see RedisConnection#getClientList() + * @since 1.3 + */ + List getClientList(); } diff --git a/src/main/java/org/springframework/data/redis/connection/convert/StringToRedisClientInfoConverter.java b/src/main/java/org/springframework/data/redis/connection/convert/StringToRedisClientInfoConverter.java new file mode 100644 index 0000000000..8c1fe74498 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/convert/StringToRedisClientInfoConverter.java @@ -0,0 +1,52 @@ +/* + * 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.convert; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.redis.core.types.RedisClientInfo; +import org.springframework.data.redis.core.types.RedisClientInfo.RedisClientInfoBuilder; + +/** + * {@link Converter} implementation to create one {@link RedisClientInfo} per line entry in given {@link String} array. + * + *
+ * ## sample of single line
+ * 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
+ * 
+ * + * @author Christoph Strobl + * @since 1.3 + */ +public class StringToRedisClientInfoConverter implements Converter> { + + @Override + public List convert(String[] lines) { + + if (lines == null) { + return Collections.emptyList(); + } + List infos = new ArrayList(lines.length); + for (String line : lines) { + infos.add(RedisClientInfoBuilder.fromString(line)); + } + return infos; + } + +} diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java index 406142381d..7671f965f7 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java @@ -42,6 +42,7 @@ import org.springframework.data.redis.connection.Subscription; import org.springframework.data.redis.connection.convert.Converters; import org.springframework.data.redis.connection.convert.TransactionResultConverter; +import org.springframework.data.redis.core.types.RedisClientInfo; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.ReflectionUtils; @@ -2854,6 +2855,18 @@ public String getClientName() { return jedis.clientGetname(); } + /* + * @see org.springframework.data.redis.connection.RedisServerCommands#getClientName() + */ + @Override + public List getClientList() { + + if (isQueueing() || isPipelined()) { + throw new UnsupportedOperationException("'CLIENT LIST' is not supported in in pipeline / multi mode."); + } + return JedisConverters.toListOfRedisClientInformation(this.jedis.clientList()); + } + /** * Specifies if pipelined results should be converted to the expected data type. If false, results of * {@link #closePipeline()} and {@link #exec()} will be of the type returned by the Jedis driver diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConverters.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConverters.java index 69c6a26639..b1bc248322 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConverters.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConverters.java @@ -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,6 +15,8 @@ */ package org.springframework.data.redis.connection.jedis; +import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.Set; @@ -31,7 +33,10 @@ import org.springframework.data.redis.connection.convert.ListConverter; import org.springframework.data.redis.connection.convert.MapConverter; import org.springframework.data.redis.connection.convert.SetConverter; +import org.springframework.data.redis.connection.convert.StringToRedisClientInfoConverter; +import org.springframework.data.redis.core.types.RedisClientInfo; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; import redis.clients.jedis.BinaryClient.LIST_POSITION; import redis.clients.jedis.BitOP; @@ -42,6 +47,7 @@ * Jedis type converters * * @author Jennifer Hickey + * @author Christoph Strobl */ abstract public class JedisConverters extends Converters { @@ -51,6 +57,7 @@ abstract public class JedisConverters extends Converters { private static final MapConverter STRING_MAP_TO_BYTE_MAP; private static final SetConverter TUPLE_SET_TO_TUPLE_SET; private static final Converter EXCEPTION_CONVERTER = new JedisExceptionConverter(); + private static final Converter> STRING_TO_CLIENT_INFO_CONVERTER = new StringToRedisClientInfoConverter(); static { STRING_TO_BYTES = new Converter() { @@ -114,6 +121,19 @@ public static String toString(byte[] source) { return source == null ? null : SafeEncoder.encode(source); } + /** + * @param source + * @return + * @since 1.3 + */ + public static List toListOfRedisClientInformation(String source) { + + if (!StringUtils.hasText(source)) { + return Collections.emptyList(); + } + return STRING_TO_CLIENT_INFO_CONVERTER.convert(source.split("\\r?\\n")); + } + public static DataAccessException toDataAccessException(Exception ex) { return EXCEPTION_CONVERTER.convert(ex); } diff --git a/src/main/java/org/springframework/data/redis/connection/jredis/JredisConnection.java b/src/main/java/org/springframework/data/redis/connection/jredis/JredisConnection.java index 24613a97f3..1f2b538a4f 100644 --- a/src/main/java/org/springframework/data/redis/connection/jredis/JredisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/jredis/JredisConnection.java @@ -43,6 +43,7 @@ import org.springframework.data.redis.connection.ReturnType; import org.springframework.data.redis.connection.SortParameters; import org.springframework.data.redis.connection.Subscription; +import org.springframework.data.redis.core.types.RedisClientInfo; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.ReflectionUtils; @@ -1204,4 +1205,8 @@ public void setClientName(byte[] name) { public String getClientName() { throw new UnsupportedOperationException("The 'CLIENT GETNAME' command is not supported by the JRedis driver."); } + + public List getClientList() { + throw new UnsupportedOperationException(); + } } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java index aa1750e253..4483b6c5ac 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java @@ -49,6 +49,7 @@ import org.springframework.data.redis.connection.Subscription; import org.springframework.data.redis.connection.convert.Converters; import org.springframework.data.redis.connection.convert.TransactionResultConverter; +import org.springframework.data.redis.core.types.RedisClientInfo; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; @@ -2959,6 +2960,21 @@ public String getClientName() { } } + @Override + public List getClientList() { + + if (isPipelined()) { + throw new UnsupportedOperationException("Cannot be called in pipeline mode."); + } + if (isQueueing()) { + transaction(new LettuceTxResult(getAsyncConnection().clientList(), + LettuceConverters.stringToRedisClientListConverter())); + return null; + } + + return LettuceConverters.toListOfRedisClientInformation(getConnection().clientList()); + } + /** * Specifies if pipelined and transaction results should be converted to the expected data type. If false, results of * {@link #closePipeline()} and {@link #exec()} will be of the type returned by the Lettuce driver diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java index 11cac3959a..6e5604c181 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java @@ -17,6 +17,7 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Date; import java.util.LinkedHashSet; import java.util.List; @@ -31,7 +32,10 @@ import org.springframework.data.redis.connection.SortParameters; import org.springframework.data.redis.connection.SortParameters.Order; import org.springframework.data.redis.connection.convert.Converters; +import org.springframework.data.redis.connection.convert.StringToRedisClientInfoConverter; +import org.springframework.data.redis.core.types.RedisClientInfo; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.ScoredValue; @@ -55,6 +59,8 @@ abstract public class LettuceConverters extends Converters { private static final Converter, Tuple> SCORED_VALUE_TO_TUPLE; private static final Converter EXCEPTION_CONVERTER = new LettuceExceptionConverter(); + private static final Converter> STRING_TO_LIST_OF_CLIENT_INFO = new StringToRedisClientInfoConverter(); + static { DATE_TO_LONG = new Converter() { public Long convert(Date source) { @@ -115,6 +121,20 @@ public Tuple convert(ScoredValue source) { }; } + public static Converter> stringToRedisClientListConverter() { + return new Converter>() { + + @Override + public List convert(String source) { + if (!StringUtils.hasText(source)) { + return Collections.emptyList(); + } + + return STRING_TO_LIST_OF_CLIENT_INFO.convert(source.split("\\r?\\n")); + } + }; + } + public static Converter dateToLong() { return DATE_TO_LONG; } @@ -235,4 +255,8 @@ public static SortArgs toSortArgs(SortParameters params) { } return args; } + + public static List toListOfRedisClientInformation(String clientList) { + return stringToRedisClientListConverter().convert(clientList); + } } diff --git a/src/main/java/org/springframework/data/redis/connection/srp/SrpConnection.java b/src/main/java/org/springframework/data/redis/connection/srp/SrpConnection.java index 7ebb9a5c43..65afaed30c 100644 --- a/src/main/java/org/springframework/data/redis/connection/srp/SrpConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/srp/SrpConnection.java @@ -40,6 +40,7 @@ import org.springframework.data.redis.connection.ReturnType; import org.springframework.data.redis.connection.SortParameters; import org.springframework.data.redis.connection.Subscription; +import org.springframework.data.redis.core.types.RedisClientInfo; import org.springframework.util.Assert; import redis.Command; @@ -2280,6 +2281,19 @@ public String getClientName() { } } + @Override + public List getClientList() { + if (isQueueing()) { + throw new UnsupportedOperationException(); + } + if (isPipelined()) { + pipeline(new SrpGenericResult(pipeline.client_list(), SrpConverters.replyToListOfRedisClientInfo())); + return null; + } + + return SrpConverters.toListOfRedisClientInformation(this.client.client_list()); + } + private List closeTransaction() { List results = Collections.emptyList(); if (txTracker != null) { diff --git a/src/main/java/org/springframework/data/redis/connection/srp/SrpConverters.java b/src/main/java/org/springframework/data/redis/connection/srp/SrpConverters.java index 6128393351..d9975aac30 100644 --- a/src/main/java/org/springframework/data/redis/connection/srp/SrpConverters.java +++ b/src/main/java/org/springframework/data/redis/connection/srp/SrpConverters.java @@ -34,6 +34,8 @@ import org.springframework.data.redis.connection.RedisStringCommands.BitOperation; import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; import org.springframework.data.redis.connection.convert.Converters; +import org.springframework.data.redis.connection.convert.StringToRedisClientInfoConverter; +import org.springframework.data.redis.core.types.RedisClientInfo; import org.springframework.util.Assert; import redis.client.RedisException; @@ -65,8 +67,12 @@ abstract public class SrpConverters extends Converters { private static final Converter BYTES_TO_STRING; private static final Converter BYTES_TO_DOUBLE; private static final Converter REPLIES_TO_TIME_AS_LONG; + private static final Converter> REPLY_T0_LIST_OF_CLIENT_INFO; + private static final Converter> STRING_TO_LIST_OF_CLIENT_INFO = new StringToRedisClientInfoConverter(); + private static final Converter> BYTEARRAY_T0_LIST_OF_CLIENT_INFO; static { + REPLIES_TO_BYTES_LIST = new Converter>() { public List convert(Reply[] replies) { if (replies == null) { @@ -85,21 +91,25 @@ public List convert(Reply[] replies) { return list; } }; + REPLIES_TO_BYTES_SET = new Converter>() { public Set convert(Reply[] source) { return source != null ? new LinkedHashSet(SrpConverters.toBytesList(source)) : null; } }; + BYTES_TO_PROPERTIES = new Converter() { public Properties convert(byte[] source) { return source != null ? SrpConverters.toProperties(new String(source, Charsets.UTF_8)) : null; } }; + BYTES_TO_DOUBLE = new Converter() { public Double convert(byte[] bytes) { return (bytes == null || bytes.length == 0 ? null : Double.valueOf(new String(bytes, Charsets.UTF_8))); } }; + REPLIES_TO_TIME_AS_LONG = new Converter() { @Override @@ -115,6 +125,7 @@ public Long convert(Reply[] reply) { } }; + REPLIES_TO_TUPLE_SET = new Converter>() { public Set convert(Reply[] byteArrays) { if (byteArrays == null) { @@ -130,6 +141,7 @@ public Set convert(Reply[] byteArrays) { return tuples; } }; + REPLIES_TO_BYTES_MAP = new Converter>() { public Map convert(Reply[] byteArrays) { if (byteArrays == null) { @@ -142,11 +154,13 @@ public Map convert(Reply[] byteArrays) { return map; } }; + BYTES_TO_STRING = new Converter() { public String convert(byte[] data) { return data != null ? new String((byte[]) data, Charsets.UTF_8) : null; } }; + REPLIES_TO_BOOLEAN_LIST = new Converter>() { public List convert(Reply[] source) { if (source == null) { @@ -159,6 +173,7 @@ public List convert(Reply[] source) { return results; } }; + REPLIES_TO_STRING_LIST = new Converter>() { public List convert(Reply[] source) { if (source == null) { @@ -171,6 +186,7 @@ public List convert(Reply[] source) { return results; } }; + REPLY_TO_STRING = new Converter() { @Override @@ -181,6 +197,32 @@ public String convert(Reply source) { return SrpConverters.toString((byte[]) source.data()); } }; + + REPLY_T0_LIST_OF_CLIENT_INFO = new Converter>() { + + @Override + public List convert(Reply source) { + + if (source == null || source.data() == null) { + return Collections.emptyList(); + } + Assert.isInstanceOf(byte[].class, source.data(), "Expected data to be an instace of byte []."); + return BYTEARRAY_T0_LIST_OF_CLIENT_INFO.convert((byte[]) source.data()); + } + }; + + BYTEARRAY_T0_LIST_OF_CLIENT_INFO = new Converter>() { + + @Override + public List convert(byte[] source) { + if (source == null || source.length == 0) { + return Collections.emptyList(); + } + + String s = SrpConverters.toString(source); + return STRING_TO_LIST_OF_CLIENT_INFO.convert(s.split("\\r?\\n")); + } + }; } public static Converter> repliesToBytesList() { @@ -227,6 +269,10 @@ public static Converter repliesToTimeAsLong() { return REPLIES_TO_TIME_AS_LONG; } + public static List toListOfRedisClientInformation(Reply reply) { + return REPLY_T0_LIST_OF_CLIENT_INFO.convert(reply); + } + public static List toBytesList(Reply[] source) { return REPLIES_TO_BYTES_LIST.convert(source); } @@ -312,4 +358,7 @@ public static List toStringList(String source) { return Collections.singletonList(source); } + public static Converter> replyToListOfRedisClientInfo() { + return BYTEARRAY_T0_LIST_OF_CLIENT_INFO; + } } diff --git a/src/main/java/org/springframework/data/redis/core/RedisOperations.java b/src/main/java/org/springframework/data/redis/core/RedisOperations.java index 2450bebf64..411d5ce469 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisOperations.java +++ b/src/main/java/org/springframework/data/redis/core/RedisOperations.java @@ -24,6 +24,7 @@ import org.springframework.data.redis.connection.DataType; import org.springframework.data.redis.core.query.SortQuery; import org.springframework.data.redis.core.script.RedisScript; +import org.springframework.data.redis.core.types.RedisClientInfo; import org.springframework.data.redis.serializer.RedisSerializer; /** @@ -174,6 +175,14 @@ T execute(RedisScript script, RedisSerializer argsSerializer, RedisSer List exec(); + /** + * /** Request information and statistics about connected clients. + * + * @return {@link List} of {@link RedisClientInfo} objects. + * @since 1.3 + */ + List clientList(); + /** * Execute a transaction, using the provided {@link RedisSerializer} to deserialize any results that are byte[]s or * Collections of byte[]s. If a result is a Map, the provided {@link RedisSerializer} will be used for both the keys diff --git a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java index 52d1478dc3..3d454ad29a 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java +++ b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java @@ -40,6 +40,7 @@ import org.springframework.data.redis.core.script.DefaultScriptExecutor; import org.springframework.data.redis.core.script.RedisScript; import org.springframework.data.redis.core.script.ScriptExecutor; +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.SerializationUtils; @@ -1007,4 +1008,15 @@ public Void doInRedis(RedisConnection connection) throws DataAccessException { } }); } + + @Override + public List clientList() { + return execute(new RedisCallback>() { + + @Override + public List doInRedis(RedisConnection connection) throws DataAccessException { + return connection.getClientList(); + } + }); + } } diff --git a/src/main/java/org/springframework/data/redis/core/types/RedisClientInfo.java b/src/main/java/org/springframework/data/redis/core/types/RedisClientInfo.java new file mode 100644 index 0000000000..583072d9ce --- /dev/null +++ b/src/main/java/org/springframework/data/redis/core/types/RedisClientInfo.java @@ -0,0 +1,285 @@ +/* + * 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 java.io.IOException; +import java.io.StringReader; +import java.util.Properties; + +import org.springframework.util.Assert; + +/** + * {@link RedisClientInfo} provides general and statistical information about client connections. + * + * @author Christoph Strobl + * @since 1.3 + */ +public class RedisClientInfo { + + public static enum INFO { + ADDRESS_PORT("addr"), FILE_DESCRIPTOR("fd"), CONNECTION_NAME("name"), CONNECTION_AGE("age"), CONNECTION_IDLE("idle"), FLAGS( + "flags"), DATABSE_ID("db"), CHANNEL_SUBSCRIBTIONS("sub"), PATTERN_SUBSCRIBTIONS("psub"), MULIT_COMMAND_CONTEXT( + "multi"), BUFFER_LENGTH("qbuf"), BUFFER_FREE_SPACE("qbuf-free"), OUTPUT_BUFFER_LENGTH("obl"), OUTPUT_LIST_LENGTH( + "oll"), OUTPUT_BUFFER_MEMORY_USAGE("omem"), EVENTS("events"), LAST_COMMAND("cmd"); + + String key; + + INFO(String key) { + this.key = key; + } + + } + + private final Properties clientProperties; + + public RedisClientInfo(Properties properties) { + + Assert.notNull(properties, "Cannot initialize client information for given 'null' properties."); + this.clientProperties = new Properties(); + this.clientProperties.putAll(properties); + } + + /** + * Get address/port of the client. + * + * @return + */ + public String getAddressPort() { + return get(INFO.ADDRESS_PORT); + } + + /** + * Get file descriptor corresponding to the socket + * + * @return + */ + public String getFileDescriptor() { + return get(INFO.FILE_DESCRIPTOR); + } + + /** + * Get the clients name. + * + * @return + */ + public String getName() { + return get(INFO.CONNECTION_NAME); + } + + /** + * Get total duration of the connection in seconds. + * + * @return + */ + public Long getAge() { + return getLongValueOf(INFO.CONNECTION_AGE); + } + + /** + * Get idle time of the connection in seconds. + * + * @return + */ + public Long getIdle() { + return getLongValueOf(INFO.CONNECTION_IDLE); + } + + /** + * Get client flags. + * + * @return + */ + public String getFlags() { + return get(INFO.FLAGS); + } + + /** + * Get current database index. + * + * @return + */ + public Long getDatabaseId() { + return getLongValueOf(INFO.DATABSE_ID); + } + + /** + * Get number of channel subscriptions. + * + * @return + */ + public Long getChannelSubscribtions() { + return getLongValueOf(INFO.CHANNEL_SUBSCRIBTIONS); + } + + /** + * Get number of pattern subscriptions. + * + * @return + */ + public Long getPatternSubscrbtions() { + return getLongValueOf(INFO.PATTERN_SUBSCRIBTIONS); + } + + /** + * Get the number of commands in a MULTI/EXEC context. + * + * @return + */ + public Long getMultiCommandContext() { + return getLongValueOf(INFO.MULIT_COMMAND_CONTEXT); + } + + /** + * Get the query buffer length. + * + * @return + */ + public Long getBufferLength() { + return getLongValueOf(INFO.BUFFER_LENGTH); + } + + /** + * Get the free space of the query buffer. + * + * @return + */ + public Long getBufferFreeSpace() { + return getLongValueOf(INFO.BUFFER_FREE_SPACE); + } + + /** + * Get the output buffer length. + * + * @return + */ + public Long getOutputBufferLength() { + return getLongValueOf(INFO.OUTPUT_BUFFER_LENGTH); + } + + /** + * Get number queued replies in output buffer. + * + * @return + */ + public Long getOutputListLength() { + return getLongValueOf(INFO.OUTPUT_LIST_LENGTH); + } + + /** + * Get output buffer memory usage. + * + * @return + */ + public Long getOutputBufferMemoryUsage() { + return getLongValueOf(INFO.OUTPUT_BUFFER_MEMORY_USAGE); + } + + /** + * Get file descriptor events. + * + * @return + */ + public String getEvents() { + return get(INFO.EVENTS); + } + + /** + * Get last command played. + * + * @return + */ + public String getLastCommand() { + return get(INFO.LAST_COMMAND); + } + + /** + * @param info must not be null + * @return {@literal null} if no entry found for requested {@link INFO}. + */ + public String get(INFO info) { + + Assert.notNull(info, "Cannot retrieve client information for 'null'."); + return get(info.key); + } + + /** + * @param key must not be {@literal null} or {@literal empty}. + * @return {@literal null} if no entry found for requested {@code key}. + */ + public String get(String key) { + + Assert.hasText(key, "Cannot get client information for 'empty' / 'null' key."); + return this.clientProperties.getProperty(key); + } + + private Long getLongValueOf(INFO info) { + + String value = get(info); + return value == null ? null : Long.valueOf(value); + } + + @Override + public String toString() { + return this.clientProperties.toString(); + } + + public static class RedisClientInfoBuilder { + + public static RedisClientInfo fromString(String source) { + + Assert.notNull(source, "Cannot read client properties form 'null'."); + Properties properties = new Properties(); + try { + properties.load(new StringReader(source.replace(' ', '\n'))); + } catch (IOException e) { + throw new IllegalArgumentException(String.format("Properties could not be loaded from String '%s'.", source), e); + } + return new RedisClientInfo(properties); + } + + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((clientProperties == null) ? 0 : clientProperties.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof RedisClientInfo)) { + return false; + } + RedisClientInfo other = (RedisClientInfo) obj; + if (clientProperties == null) { + if (other.clientProperties != null) { + return false; + } + } else if (!clientProperties.equals(other.clientProperties)) { + return false; + } + return true; + } + +} diff --git a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java index 9929e223a1..c7ec620995 100644 --- a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java @@ -38,6 +38,7 @@ 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; @@ -1892,6 +1893,19 @@ public void clientSetNameWorksCorrectly() { connection.setClientName("foo".getBytes()); } + /** + * @see DATAREDIS-268 + */ + @Test + public void testListClientsContainsAtLeastOneElement() { + + actual.add(connection.getClientList()); + + List results = getResults(); + assertNotNull(results.get(0)); + assertThat(((List) results.get(0)).size(), IsNot.not(0)); + } + protected void verifyResults(List expected) { assertEquals(expected, getResults()); } diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionPipelineIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionPipelineIntegrationTests.java index f6994aad1d..807b0270f1 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionPipelineIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionPipelineIntegrationTests.java @@ -254,4 +254,13 @@ public void testZAddMultiple() { public void clientSetNameWorksCorrectly() { super.clientSetNameWorksCorrectly(); } + + /** + * @see DATAREDIS-268 + */ + @Override + @Test(expected = UnsupportedOperationException.class) + public void testListClientsContainsAtLeastOneElement() { + super.testListClientsContainsAtLeastOneElement(); + } } diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionPipelineTxIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionPipelineTxIntegrationTests.java index 792f2c81ad..3435fdd9bb 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionPipelineTxIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionPipelineTxIntegrationTests.java @@ -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.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") @@ -50,4 +68,13 @@ protected List getResults() { // 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(); + } } diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionTransactionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionTransactionIntegrationTests.java index a3435b7de3..0501fd8983 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionTransactionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionTransactionIntegrationTests.java @@ -200,4 +200,12 @@ public void clientSetNameWorksCorrectly() { super.clientSetNameWorksCorrectly(); } + /** + * @see DATAREDIS-268 + */ + @Override + @Test(expected = UnsupportedOperationException.class) + public void testListClientsContainsAtLeastOneElement() { + super.testListClientsContainsAtLeastOneElement(); + } } diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConvertersUnitTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConvertersUnitTests.java new file mode 100644 index 0000000000..ccf3e59559 --- /dev/null +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConvertersUnitTests.java @@ -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. emptyList())); + } + + /** + * @see DATAREDIS-268 + */ + @Test + public void convertingNullToListOfRedisClientInfoShouldReturnEmptyList() { + assertThat(JedisConverters.toListOfRedisClientInformation(null), equalTo(Collections. 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)); + } +} diff --git a/src/test/java/org/springframework/data/redis/connection/jredis/JRedisConnectionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/jredis/JRedisConnectionIntegrationTests.java index ab30964d30..ad97078877 100644 --- a/src/test/java/org/springframework/data/redis/connection/jredis/JRedisConnectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jredis/JRedisConnectionIntegrationTests.java @@ -818,4 +818,13 @@ public void testPsetEx() throws Exception { public void clientSetNameWorksCorrectly() { super.clientSetNameWorksCorrectly(); } + + /** + * @see DATAREDIS-268 + */ + @Override + @Test(expected = UnsupportedOperationException.class) + public void testListClientsContainsAtLeastOneElement() { + super.testListClientsContainsAtLeastOneElement(); + } } diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineIntegrationTests.java index 58a6943e3c..db102aa3c4 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineIntegrationTests.java @@ -113,4 +113,13 @@ public void testMove() { } } + /** + * @see DATAREDIS-268 + */ + @Override + @Test(expected = UnsupportedOperationException.class) + public void testListClientsContainsAtLeastOneElement() { + super.testListClientsContainsAtLeastOneElement(); + } + } diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineTxIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineTxIntegrationTests.java index 59aa57d2fb..67d9b2e63d 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineTxIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionPipelineTxIntegrationTests.java @@ -83,4 +83,13 @@ protected List getResults() { return txResults; } + /** + * @see DATAREDIS-268 + */ + @Override + @Test(expected = UnsupportedOperationException.class) + public void testListClientsContainsAtLeastOneElement() { + super.testListClientsContainsAtLeastOneElement(); + } + } diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConvertersUnitTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConvertersUnitTests.java new file mode 100644 index 0000000000..aa605c964a --- /dev/null +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConvertersUnitTests.java @@ -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. emptyList())); + } + + /** + * @see DATAREDIS-268 + */ + @Test + public void convertingNullToListOfRedisClientInfoShouldReturnEmptyList() { + assertThat(LettuceConverters.toListOfRedisClientInformation(null), + equalTo(Collections. 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)); + } + +} diff --git a/src/test/java/org/springframework/data/redis/connection/srp/SrpConnectionTransactionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/srp/SrpConnectionTransactionIntegrationTests.java index d636c2261a..bf9d5dd5ae 100644 --- a/src/test/java/org/springframework/data/redis/connection/srp/SrpConnectionTransactionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/srp/SrpConnectionTransactionIntegrationTests.java @@ -59,4 +59,12 @@ public void testZInterStoreAggWeights() { public void testZUnionStoreAggWeights() { super.testZUnionStoreAggWeights(); } + + /** + * @see DATAREDIS-268 + */ + @Test(expected = UnsupportedOperationException.class) + public void testListClientsContainsAtLeastOneElement() { + super.testListClientsContainsAtLeastOneElement(); + } } diff --git a/src/test/java/org/springframework/data/redis/connection/srp/SrpConvertersUnitTests.java b/src/test/java/org/springframework/data/redis/connection/srp/SrpConvertersUnitTests.java new file mode 100644 index 0000000000..c33619d07e --- /dev/null +++ b/src/test/java/org/springframework/data/redis/connection/srp/SrpConvertersUnitTests.java @@ -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. emptyList())); + } + + /** + * @see DATAREDIS-268 + */ + @Test + public void convertingEmptyReplyToListOfRedisClientInfoShouldReturnEmptyList() { + assertThat(SrpConverters.toListOfRedisClientInformation(new BulkReply(new byte[0])), + equalTo(Collections. emptyList())); + } + + /** + * @see DATAREDIS-268 + */ + @Test + public void convertingNullToListOfRedisClientInfoShouldReturnEmptyList() { + assertThat(SrpConverters.toListOfRedisClientInformation(null), equalTo(Collections. 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() { + + @Override + public String data() { + return "foo"; + } + + @Override + public void write(OutputStream os) throws IOException { + // just do nothing; + } + }); + } +} diff --git a/src/test/java/org/springframework/data/redis/core/RedisTemplateTests.java b/src/test/java/org/springframework/data/redis/core/RedisTemplateTests.java index 57f4e8b73d..1d377d6f22 100644 --- a/src/test/java/org/springframework/data/redis/core/RedisTemplateTests.java +++ b/src/test/java/org/springframework/data/redis/core/RedisTemplateTests.java @@ -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.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 @@ * Integration test of {@link RedisTemplate} * * @author Jennifer Hickey + * @author Christoph Strobl */ @RunWith(Parameterized.class) public class RedisTemplateTests { @@ -703,6 +700,11 @@ public void testExecuteScriptCustomSerializers() { Collections.singletonList(key1))); } + @Test + public void clientListShouldReturnCorrectly() { + assertThat(redisTemplate.clientList().size(), IsNot.not(0)); + } + @SuppressWarnings({ "unchecked", "rawtypes" }) private byte[] serialize(Object value, RedisSerializer serializer) { if (serializer == null && value instanceof byte[]) { diff --git a/src/test/java/org/springframework/data/redis/core/types/RedisClientInfoUnitTests.java b/src/test/java/org/springframework/data/redis/core/types/RedisClientInfoUnitTests.java new file mode 100644 index 0000000000..5f7bbc3b7c --- /dev/null +++ b/src/test/java/org/springframework/data/redis/core/types/RedisClientInfoUnitTests.java @@ -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)); + } + } + + } + +}