From d09de96c0e3f52d18130253fa389ef2f66e6949d Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Sun, 4 Jun 2023 23:42:24 +0600 Subject: [PATCH 01/10] Use List to read RESP3 Map reply --- .../redis/clients/jedis/BuilderFactory.java | 375 +++++++++--------- .../redis/clients/jedis/CommandObjects.java | 9 +- src/main/java/redis/clients/jedis/Jedis.java | 66 +-- src/main/java/redis/clients/jedis/Module.java | 20 + .../java/redis/clients/jedis/Protocol.java | 37 +- .../AccessControlLogBinaryCommands.java | 18 +- .../commands/AccessControlLogCommands.java | 18 +- .../jedis/commands/ConfigCommands.java | 14 +- .../jedis/resps/AccessControlLogEntry.java | 1 + .../jedis/resps/AccessControlUser.java | 113 ++++-- .../clients/jedis/resps/CommandDocument.java | 37 +- .../clients/jedis/resps/FunctionStats.java | 35 +- .../clients/jedis/resps/LibraryInfo.java | 42 +- .../redis/clients/jedis/resps/Slowlog.java | 11 +- .../redis/clients/jedis/util/SafeEncoder.java | 5 + .../jedis/AccessControlListCommandsTest.java | 8 +- .../jedis/AllKindOfValuesCommandsTest.java | 86 +++- .../commands/jedis/ControlCommandsTest.java | 36 +- .../commands/jedis/JedisCommandsTestBase.java | 8 +- .../jedis/commands/jedis/ModuleTest.java | 4 +- .../commands/jedis/ScriptingCommandsTest.java | 40 +- .../commands/jedis/SlowlogCommandsTest.java | 49 ++- .../commands/jedis/StreamsCommandsTest.java | 2 +- .../pooled/PooledCommandsTestHelper.java | 4 +- 24 files changed, 630 insertions(+), 408 deletions(-) diff --git a/src/main/java/redis/clients/jedis/BuilderFactory.java b/src/main/java/redis/clients/jedis/BuilderFactory.java index b54ee8222a0..3cf42e65f13 100644 --- a/src/main/java/redis/clients/jedis/BuilderFactory.java +++ b/src/main/java/redis/clients/jedis/BuilderFactory.java @@ -63,19 +63,6 @@ public String toString() { } }; - public static final Builder> ENCODED_OBJECT_MAP = new Builder>() { - @Override - public Map build(Object data) { - final List list = (List) data; - final Map map = new HashMap<>(list.size() / 2, 1f); - final Iterator iterator = list.iterator(); - while (iterator.hasNext()) { - map.put(STRING.build(iterator.next()), ENCODED_OBJECT.build(iterator.next())); - } - return map; - } - }; - public static final Builder LONG = new Builder() { @Override public Long build(Object data) { @@ -221,26 +208,6 @@ public String toString() { } }; - public static final Builder> BINARY_MAP = new Builder>() { - @Override - @SuppressWarnings("unchecked") - public Map build(Object data) { - final List flatHash = (List) data; - final Map hash = new JedisByteHashMap(); - final Iterator iterator = flatHash.iterator(); - while (iterator.hasNext()) { - hash.put(iterator.next(), iterator.next()); - } - - return hash; - } - - @Override - public String toString() { - return "Map"; - } - }; - public static final Builder>> BINARY_PAIR_LIST = new Builder>>() { @Override @@ -323,18 +290,86 @@ public String toString() { } }; + public static final Builder> ENCODED_OBJECT_MAP = new Builder>() { + @Override + public Map build(Object data) { + if (data == null) return null; + final List list = (List) data; + if (list.isEmpty()) return Collections.emptyMap(); + + if (list.get(0) instanceof KeyValue) { + final Map map = new HashMap<>(list.size(), 1f); + final Iterator iterator = list.iterator(); + while (iterator.hasNext()) { + KeyValue kv = (KeyValue) iterator.next(); + map.put(STRING.build(kv.getKey()), ENCODED_OBJECT.build(kv.getValue())); + } + return map; + } else { + final Map map = new HashMap<>(list.size() / 2, 1f); + final Iterator iterator = list.iterator(); + while (iterator.hasNext()) { + map.put(STRING.build(iterator.next()), ENCODED_OBJECT.build(iterator.next())); + } + return map; + } + } + }; + + public static final Builder> BINARY_MAP = new Builder>() { + @Override + @SuppressWarnings("unchecked") + public Map build(Object data) { + final List list = (List) data; + if (list.isEmpty()) return Collections.emptyMap(); + + if (list.get(0) instanceof KeyValue) { + final Map map = new JedisByteHashMap(); + final Iterator iterator = list.iterator(); + while (iterator.hasNext()) { + KeyValue kv = (KeyValue) iterator.next(); + map.put(BINARY.build(kv.getKey()), BINARY.build(kv.getValue())); + } + return map; + } else { + final Map map = new JedisByteHashMap(); + final Iterator iterator = list.iterator(); + while (iterator.hasNext()) { + map.put(BINARY.build(iterator.next()), BINARY.build(iterator.next())); + } + return map; + } + } + + @Override + public String toString() { + return "Map"; + } + }; + public static final Builder> STRING_MAP = new Builder>() { @Override @SuppressWarnings("unchecked") public Map build(Object data) { - final List flatHash = (List) data; - final Map hash = new HashMap<>(flatHash.size() / 2, 1f); - final Iterator iterator = flatHash.iterator(); - while (iterator.hasNext()) { - hash.put(SafeEncoder.encode(iterator.next()), SafeEncoder.encode(iterator.next())); + final List list = (List) data; + if (list.isEmpty()) return Collections.emptyMap(); + + if (list.get(0) instanceof KeyValue) { + final Map map = new HashMap<>(list.size(), 1f); + final Iterator iterator = list.iterator(); + while (iterator.hasNext()) { + KeyValue kv = (KeyValue) iterator.next(); + map.put(STRING.build(kv.getKey()), STRING.build(kv.getValue())); + } + return map; + } else { + final Map map = new HashMap<>(list.size() / 2, 1f); + final Iterator iterator = list.iterator(); + while (iterator.hasNext()) { + map.put(STRING.build(iterator.next()), STRING.build(iterator.next())); + } + return map; } - - return hash; } @Override @@ -852,20 +887,26 @@ public String toString() { public static final Builder> COMMAND_DOCS_RESPONSE = new Builder>() { @Override public Map build(Object data) { - if (data == null) { - return null; - } - + if (data == null) return null; List list = (List) data; - Map map = new HashMap<>(list.size() / 2, 1f); - - for (int i = 0; i < list.size();) { - String name = STRING.build(list.get(i++)); - CommandDocument doc = CommandDocument.COMMAND_DOCUMENT_BUILDER.build(list.get(i++)); - map.put(name, doc); + if (list.isEmpty()) return Collections.emptyMap(); + + if (list.get(0) instanceof KeyValue) { + final Map map = new HashMap<>(list.size(), 1f); + final Iterator iterator = list.iterator(); + while (iterator.hasNext()) { + KeyValue kv = (KeyValue) iterator.next(); + map.put(STRING.build(kv.getKey()), new CommandDocument(ENCODED_OBJECT_MAP.build(kv.getValue()))); + } + return map; + } else { + final Map map = new HashMap<>(list.size() / 2, 1f); + final Iterator iterator = list.iterator(); + while (iterator.hasNext()) { + map.put(STRING.build(iterator.next()), new CommandDocument(ENCODED_OBJECT_MAP.build(iterator.next()))); + } + return map; } - - return map; } }; @@ -894,27 +935,28 @@ public Map build(Object data) { } }; - public static final Builder> MODULE_LIST = new Builder>() { + public static final Builder>> ENCODED_OBJECT_MAP_LIST = new Builder>>() { @Override - public List build(Object data) { - if (data == null) { - return null; - } - - List> objectList = (List>) data; + public List> build(Object data) { + if (data == null) return null; + List list = (List) data; + if (list.isEmpty()) return Collections.emptyList(); - List responses = new ArrayList<>(objectList.size()); - if (objectList.isEmpty()) { - return responses; - } + return list.stream().map(ENCODED_OBJECT_MAP::build).collect(Collectors.toList()); + } - for (List moduleResp : objectList) { - Module m = new Module(SafeEncoder.encode((byte[]) moduleResp.get(1)), - ((Long) moduleResp.get(3)).intValue()); - responses.add(m); - } + @Override + public String toString() { + return "List>"; + } + }; - return responses; + public static final Builder> MODULE_LIST = new Builder>() { + @Override + public List build(Object data) { + List> list = ENCODED_OBJECT_MAP_LIST.build(data); + if (list == null) return null; + return list.stream().map(Module::new).collect(Collectors.toList()); } @Override @@ -927,74 +969,17 @@ public String toString() { * Create a AccessControlUser object from the ACL GETUSER reply. */ public static final Builder ACCESS_CONTROL_USER = new Builder() { - @SuppressWarnings("unchecked") @Override public AccessControlUser build(Object data) { - if (data == null) { - return null; - } - - List objectList = (List) data; - if (objectList.isEmpty()) { - return null; - } - - AccessControlUser accessControlUser = new AccessControlUser(); - - // flags - List flags = (List) objectList.get(1); - for (Object f : flags) { - accessControlUser.addFlag(SafeEncoder.encode((byte[]) f)); - } - - // passwords - List passwords = (List) objectList.get(3); - for (Object p : passwords) { - accessControlUser.addPassword(SafeEncoder.encode((byte[]) p)); - } - - // commands - accessControlUser.setCommands(SafeEncoder.encode((byte[]) objectList.get(5))); - - // Redis 7 --> - boolean withSelectors = objectList.size() >= 12; - if (!withSelectors) { - - // keys - List keys = (List) objectList.get(7); - for (Object k : keys) { - accessControlUser.addKey(SafeEncoder.encode((byte[]) k)); - } - - // Redis 6.2 --> - // channels - if (objectList.size() >= 10) { - List channels = (List) objectList.get(9); - for (Object channel : channels) { - accessControlUser.addChannel(SafeEncoder.encode((byte[]) channel)); - } - } - - } else { - // TODO: Proper implementation of ACL V2. - - // keys - accessControlUser.addKeys(SafeEncoder.encode((byte[]) objectList.get(7))); - - // channels - accessControlUser.addChannels(SafeEncoder.encode((byte[]) objectList.get(9))); - } - - // selectors - // TODO: Proper implementation of ACL V2. - return accessControlUser; + Map map = ENCODED_OBJECT_MAP.build(data); + if (map == null) return null; + return new AccessControlUser(map); } @Override public String toString() { return "AccessControlUser"; } - }; /** @@ -1210,41 +1195,24 @@ public String toString() { @Override public List>> build(Object data) { if (data == null) return null; - List streamObjects = (List) data; - - List>> result = new ArrayList<>(streamObjects.size()); - for (Object streamObj : streamObjects) { - List stream = (List) streamObj; - String streamKey = STRING.build(stream.get(0)); - List streamEntries = STREAM_ENTRY_LIST.build(stream.get(1)); - result.add(KeyValue.of(streamKey, streamEntries)); - } - - return result; - } - - @Override - public String toString() { - return "List>>"; - } - }; - - public static final Builder>>> STREAM_READ_RESPONSE_RESP3 - = new Builder>>>() { - @Override - public List>> build(Object data) { - if (data == null) return null; - List streamObjects = (List) data; - - List>> result = new ArrayList<>(streamObjects.size() / 2); - Iterator iter = streamObjects.iterator(); - while (iter.hasNext()) { - String streamKey = STRING.build(iter.next()); - List streamEntries = STREAM_ENTRY_LIST.build(iter.next()); - result.add(KeyValue.of(streamKey, streamEntries)); + List list = (List) data; + if (list.isEmpty()) return Collections.emptyList(); + + if (list.get(0) instanceof KeyValue) { + return ((List) list).stream() + .map(kv -> new KeyValue<>(STRING.build(kv.getKey()), + STREAM_ENTRY_LIST.build(kv.getValue()))) + .collect(Collectors.toList()); + } else { + List>> result = new ArrayList<>(list.size()); + for (Object streamObj : list) { + List stream = (List) streamObj; + String streamKey = STRING.build(stream.get(0)); + List streamEntries = STREAM_ENTRY_LIST.build(stream.get(1)); + result.add(KeyValue.of(streamKey, streamEntries)); + } + return result; } - - return result; } @Override @@ -1628,18 +1596,32 @@ private static Map createMapFromDecodingFunctions(Iterator createMapFromDecodingFunctions(Iterator iterator, Map mappingFunctions, Collection backupBuilders) { + if (!iterator.hasNext()) { + return Collections.emptyMap(); + } + Map resultMap = new HashMap<>(); while (iterator.hasNext()) { + final Object tempObject = iterator.next(); + final String mapKey; + final Object rawValue; + + if (tempObject instanceof KeyValue) { + KeyValue kv = (KeyValue) tempObject; + mapKey = STRING.build(kv.getKey()); + rawValue = kv.getValue(); + } else { + mapKey = STRING.build(iterator.next()); + rawValue = iterator.next(); + } - String mapKey = STRING.build(iterator.next()); if (mappingFunctions.containsKey(mapKey)) { - resultMap.put(mapKey, mappingFunctions.get(mapKey).build(iterator.next())); + resultMap.put(mapKey, mappingFunctions.get(mapKey).build(rawValue)); } else { // For future - if we don't find an element in our builder map - Object unknownData = iterator.next(); Collection builders = backupBuilders != null ? backupBuilders : mappingFunctions.values(); for (Builder b : builders) { try { - resultMap.put(mapKey, b.build(unknownData)); + resultMap.put(mapKey, b.build(rawValue)); break; } catch (ClassCastException e) { // We continue with next builder @@ -1668,34 +1650,51 @@ public LCSMatchResult build(Object data) { List matchedPositions = new ArrayList<>(); List objectList = (List) data; - if ("matches".equalsIgnoreCase(STRING.build(objectList.get(0)))) { - List matches = (List)objectList.get(1); - for (Object obj : matches) { - if (obj instanceof List) { - List positions = (List) obj; - Position a = new Position( - LONG.build(((List) positions.get(0)).get(0)), - LONG.build(((List) positions.get(0)).get(1)) - ); - Position b = new Position( - LONG.build(((List) positions.get(1)).get(0)), - LONG.build(((List) positions.get(1)).get(1)) - ); - long matchLen = 0; - if (positions.size() >= 3) { - matchLen = LONG.build(positions.get(2)); - } - matchedPositions.add(new MatchedPosition(a, b, matchLen)); + if (objectList.get(0) instanceof KeyValue) { + Iterator iterator = objectList.iterator(); + while (iterator.hasNext()) { + KeyValue kv = (KeyValue) iterator.next(); + if ("matches".equalsIgnoreCase(STRING.build(kv.getKey()))) { + addMatchedPosition(matchedPositions, kv.getValue()); + } else if ("len".equalsIgnoreCase(STRING.build(kv.getKey()))) { + len = LONG.build(kv.getValue()); + } + } + } else { + for (int i = 0; i < objectList.size(); i++) { + if ("matches".equalsIgnoreCase(STRING.build(objectList.get(i)))) { + addMatchedPosition(matchedPositions, objectList.get(i + 1)); + } else if ("len".equalsIgnoreCase(STRING.build(objectList.get(i)))) { + len = LONG.build(objectList.get(i + 1)); } } } - if ("len".equalsIgnoreCase(STRING.build(objectList.get(2)))) { - len = LONG.build(objectList.get(3)); - } return new LCSMatchResult(matchedPositions, len); } } + + private void addMatchedPosition(List matchedPositions, Object o) { + List matches = (List) o; + for (Object obj : matches) { + if (obj instanceof List) { + List positions = (List) obj; + Position a = new Position( + LONG.build(((List) positions.get(0)).get(0)), + LONG.build(((List) positions.get(0)).get(1)) + ); + Position b = new Position( + LONG.build(((List) positions.get(1)).get(0)), + LONG.build(((List) positions.get(1)).get(1)) + ); + long matchLen = 0; + if (positions.size() >= 3) { + matchLen = LONG.build(positions.get(2)); + } + matchedPositions.add(new MatchedPosition(a, b, matchLen)); + } + } + } }; public static final Builder> STRING_MAP_FROM_PAIRS = new Builder>() { diff --git a/src/main/java/redis/clients/jedis/CommandObjects.java b/src/main/java/redis/clients/jedis/CommandObjects.java index 462e6a083c1..05012ef86e8 100644 --- a/src/main/java/redis/clients/jedis/CommandObjects.java +++ b/src/main/java/redis/clients/jedis/CommandObjects.java @@ -2635,7 +2635,7 @@ public final CommandObject>>> xread( Set> entrySet = streams.entrySet(); entrySet.forEach(entry -> args.key(entry.getKey())); entrySet.forEach(entry -> args.add(entry.getValue())); - return new CommandObject<>(args, getStreamReadResponseBuilder()); + return new CommandObject<>(args, BuilderFactory.STREAM_READ_RESPONSE); } public final CommandObject>>> xreadGroup( @@ -2647,7 +2647,7 @@ public final CommandObject>>> xreadGrou Set> entrySet = streams.entrySet(); entrySet.forEach(entry -> args.key(entry.getKey())); entrySet.forEach(entry -> args.add(entry.getValue())); - return new CommandObject<>(args, getStreamReadResponseBuilder()); + return new CommandObject<>(args, BuilderFactory.STREAM_READ_RESPONSE); } public final CommandObject> xread(XReadParams xReadParams, Map.Entry... streams) { @@ -2674,11 +2674,6 @@ public final CommandObject> xreadGroup(byte[] groupName, byte[] con } return new CommandObject<>(args, BuilderFactory.BINARY_LIST); } - - private Builder>>> getStreamReadResponseBuilder() { - if (proto == RedisProtocol.RESP3) return BuilderFactory.STREAM_READ_RESPONSE_RESP3; - return BuilderFactory.STREAM_READ_RESPONSE; - } // Stream commands // Scripting commands diff --git a/src/main/java/redis/clients/jedis/Jedis.java b/src/main/java/redis/clients/jedis/Jedis.java index fc49d9761c5..cad26491693 100644 --- a/src/main/java/redis/clients/jedis/Jedis.java +++ b/src/main/java/redis/clients/jedis/Jedis.java @@ -3572,17 +3572,17 @@ public List roleBinary() { * @return Bulk reply. */ @Override - public List configGet(final byte[] pattern) { + public Map configGet(final byte[] pattern) { checkIsInMultiOrPipeline(); connection.sendCommand(Command.CONFIG, Keyword.GET.getRaw(), pattern); - return connection.getBinaryMultiBulkReply(); + return BuilderFactory.BINARY_MAP.build(connection.getOne()); } @Override - public List configGet(byte[]... patterns) { + public Map configGet(byte[]... patterns) { checkIsInMultiOrPipeline(); connection.sendCommand(Command.CONFIG, joinParameters(Keyword.GET.getRaw(), patterns)); - return connection.getBinaryMultiBulkReply(); + return BuilderFactory.BINARY_MAP.build(connection.getOne()); } /** @@ -3671,6 +3671,15 @@ public String configSet(final byte[]... parameterValues) { return connection.getStatusCodeReply(); } + @Override + public String configSetBinary(Map parameterValues) { + checkIsInMultiOrPipeline(); + CommandArguments args = new CommandArguments(Command.CONFIG).add(Keyword.SET); + parameterValues.forEach((k, v) -> args.add(k).add(v)); + connection.sendCommand(args); + return connection.getStatusCodeReply(); + } + @Override public long strlen(final byte[] key) { checkIsInMultiOrPipeline(); @@ -4109,23 +4118,16 @@ public String aclSetUser(byte[] name) { } @Override - public String aclSetUser(byte[] name, byte[]... keys) { + public String aclSetUser(byte[] name, byte[]... rules) { checkIsInMultiOrPipeline(); - connection.sendCommand(ACL, joinParameters(SETUSER.getRaw(), name, keys)); + connection.sendCommand(ACL, joinParameters(SETUSER.getRaw(), name, rules)); return connection.getStatusCodeReply(); } @Override - public long aclDelUser(byte[] name) { + public long aclDelUser(byte[]... names) { checkIsInMultiOrPipeline(); - connection.sendCommand(ACL, DELUSER.getRaw(), name); - return connection.getIntegerReply(); - } - - @Override - public long aclDelUser(byte[] name, byte[]... names) { - checkIsInMultiOrPipeline(); - connection.sendCommand(ACL, joinParameters(DELUSER.getRaw(), name, names)); + connection.sendCommand(ACL, joinParameters(DELUSER.getRaw(), names)); return connection.getIntegerReply(); } @@ -7864,17 +7866,17 @@ public List role() { * @return Bulk reply. */ @Override - public List configGet(final String pattern) { + public Map configGet(final String pattern) { checkIsInMultiOrPipeline(); connection.sendCommand(Command.CONFIG, Keyword.GET.name(), pattern); - return connection.getMultiBulkReply(); + return BuilderFactory.STRING_MAP.build(connection.getOne()); } @Override - public List configGet(String... patterns) { + public Map configGet(String... patterns) { checkIsInMultiOrPipeline(); connection.sendCommand(Command.CONFIG, joinParameters(Keyword.GET.name(), patterns)); - return connection.getMultiBulkReply(); + return BuilderFactory.STRING_MAP.build(connection.getOne()); } /** @@ -7920,6 +7922,15 @@ public String configSet(final String... parameterValues) { return connection.getStatusCodeReply(); } + @Override + public String configSet(Map parameterValues) { + checkIsInMultiOrPipeline(); + CommandArguments args = new CommandArguments(Command.CONFIG).add(Keyword.SET); + parameterValues.forEach((k, v) -> args.add(k).add(v)); + connection.sendCommand(args); + return connection.getStatusCodeReply(); + } + public long publish(final String channel, final String message) { checkIsInMultiOrPipeline(); connection.sendCommand(PUBLISH, channel, message); @@ -8360,23 +8371,16 @@ public String aclSetUser(final String name) { } @Override - public String aclSetUser(String name, String... params) { + public String aclSetUser(String name, String... rules) { checkIsInMultiOrPipeline(); - connection.sendCommand(ACL, joinParameters(SETUSER.name(), name, params)); + connection.sendCommand(ACL, joinParameters(SETUSER.name(), name, rules)); return connection.getStatusCodeReply(); } @Override - public long aclDelUser(final String name) { + public long aclDelUser(final String... names) { checkIsInMultiOrPipeline(); - connection.sendCommand(ACL, DELUSER.name(), name); - return connection.getIntegerReply(); - } - - @Override - public long aclDelUser(final String name, String... names) { - checkIsInMultiOrPipeline(); - connection.sendCommand(ACL, joinParameters(DELUSER.name(), name, names)); + connection.sendCommand(ACL, joinParameters(DELUSER.name(), names)); return connection.getIntegerReply(); } @@ -8384,7 +8388,7 @@ public long aclDelUser(final String name, String... names) { public AccessControlUser aclGetUser(final String name) { checkIsInMultiOrPipeline(); connection.sendCommand(ACL, GETUSER.name(), name); - return BuilderFactory.ACCESS_CONTROL_USER.build(connection.getObjectMultiBulkReply()); + return BuilderFactory.ACCESS_CONTROL_USER.build(connection.getOne()); } @Override diff --git a/src/main/java/redis/clients/jedis/Module.java b/src/main/java/redis/clients/jedis/Module.java index 3dbf9b46cff..833bf5aa6bb 100644 --- a/src/main/java/redis/clients/jedis/Module.java +++ b/src/main/java/redis/clients/jedis/Module.java @@ -1,13 +1,26 @@ package redis.clients.jedis; +import java.util.Map; + +// TODO: 'resps' package +// TODO: remove public class Module { + private final Map info; private final String name; private final int version; + @Deprecated public Module(String name, int version) { this.name = name; this.version = version; + this.info = null; + } + + public Module(Map map) { + this.info = map; + this.name = (String) map.get("name"); + this.version = ((Long) map.get("version")).intValue(); } public String getName() { @@ -18,6 +31,13 @@ public int getVersion() { return version; } + /** + * @return Generic map containing all key-value pairs returned by the server + */ + public Map getInfo() { + return info; + } + @Override public boolean equals(Object o) { if (o == null) return false; diff --git a/src/main/java/redis/clients/jedis/Protocol.java b/src/main/java/redis/clients/jedis/Protocol.java index 154549d2a31..3f273877b59 100644 --- a/src/main/java/redis/clients/jedis/Protocol.java +++ b/src/main/java/redis/clients/jedis/Protocol.java @@ -10,6 +10,7 @@ import redis.clients.jedis.exceptions.*; import redis.clients.jedis.args.Rawable; import redis.clients.jedis.commands.ProtocolCommand; +import redis.clients.jedis.util.KeyValue; import redis.clients.jedis.util.RedisInputStream; import redis.clients.jedis.util.RedisOutputStream; import redis.clients.jedis.util.SafeEncoder; @@ -133,7 +134,6 @@ private static String[] parseTargetHostAndSlot(String clusterRedirectResponse) { private static Object process(final RedisInputStream is) { final byte b = is.readByte(); //System.out.println((char) b); - int num; switch (b) { case PLUS_BYTE: return is.readLineBytes(); @@ -141,9 +141,7 @@ private static Object process(final RedisInputStream is) { case EQUAL_BYTE: return processBulkReply(is); case ASTERISK_BYTE: - num = is.readIntCrLf(); - if (num == -1) return null; - return processMultiBulkReply(num, is); + return processMultiBulkReply(is); case UNDERSCORE_BYTE: return is.readNullCrLf(); case HASH_BYTE: @@ -155,17 +153,11 @@ private static Object process(final RedisInputStream is) { case LEFT_BRACE_BYTE: return is.readBigIntegerCrLf(); case PERCENT_BYTE: // TODO: currently just to start working with HELLO - num = is.readIntCrLf(); - if (num == -1) return null; - return processMultiBulkReply(2 * num, is); + return processMapKeyValueReply(is); case TILDE_BYTE: // TODO: - num = is.readIntCrLf(); - if (num == -1) return null; - return processMultiBulkReply(num, is); + return processMultiBulkReply(is); case GREATER_THAN_BYTE: - num = is.readIntCrLf(); - if (num == -1) return null; - return processMultiBulkReply(num, is); + return processMultiBulkReply(is); case MINUS_BYTE: processError(is); return null; @@ -198,9 +190,10 @@ private static byte[] processBulkReply(final RedisInputStream is) { return read; } - // private static List processMultiBulkReply(final RedisInputStream is) { - private static List processMultiBulkReply(final int num, final RedisInputStream is) { - // final int num = is.readIntCrLf(); + private static List processMultiBulkReply(final RedisInputStream is) { + // private static List processMultiBulkReply(final int num, final RedisInputStream is) { + final int num = is.readIntCrLf(); + if (num == -1) return null; final List ret = new ArrayList<>(num); for (int i = 0; i < num; i++) { try { @@ -212,6 +205,18 @@ private static List processMultiBulkReply(final int num, final RedisInpu return ret; } + // private static List processMultiBulkReply(final RedisInputStream is) { + // private static List processMultiBulkReply(final int num, final RedisInputStream is) { + private static List processMapKeyValueReply(final RedisInputStream is) { + final int num = is.readIntCrLf(); + if (num == -1) return null; + final List ret = new ArrayList<>(num); + for (int i = 0; i < num; i++) { + ret.add(new KeyValue(process(is), process(is))); + } + return ret; + } + public static Object read(final RedisInputStream is) { return process(is); } diff --git a/src/main/java/redis/clients/jedis/commands/AccessControlLogBinaryCommands.java b/src/main/java/redis/clients/jedis/commands/AccessControlLogBinaryCommands.java index 925286d38f4..98aaec8c61f 100644 --- a/src/main/java/redis/clients/jedis/commands/AccessControlLogBinaryCommands.java +++ b/src/main/java/redis/clients/jedis/commands/AccessControlLogBinaryCommands.java @@ -74,30 +74,20 @@ public interface AccessControlLogBinaryCommands { * Create an ACL for the specified user, while specifying the rules. * * @param name user who receives an acl - * @param keys the acl rules for the specified user + * @param rules the acl rules for the specified user * @see ACL SETUSER * @return A string containing OK on success */ - String aclSetUser(byte[] name, byte[]... keys); + String aclSetUser(byte[] name, byte[]... rules); /** * Delete the specified user, from the ACL. * - * @param name The username to delete + * @param names The username to delete * @see ACL DELUSER * @return The number of users delete */ - long aclDelUser(byte[] name); - - /** - * Delete the specified users, from the ACL. - * - * @param name The username to delete - * @param names Other usernames to delete - * @see ACL DELUSER - * @return The number of users delete - */ - long aclDelUser(byte[] name, byte[]... names); + long aclDelUser(byte[]... names); /** * Show the available ACL categories. diff --git a/src/main/java/redis/clients/jedis/commands/AccessControlLogCommands.java b/src/main/java/redis/clients/jedis/commands/AccessControlLogCommands.java index b6f6b85cded..a65207c038a 100644 --- a/src/main/java/redis/clients/jedis/commands/AccessControlLogCommands.java +++ b/src/main/java/redis/clients/jedis/commands/AccessControlLogCommands.java @@ -76,30 +76,20 @@ public interface AccessControlLogCommands { * Create an ACL for the specified user, while specifying the rules. * * @param name user who receives an acl - * @param keys the acl rules for the specified user + * @param rules the acl rules for the specified user * @see ACL SETUSER * @return A string containing OK on success */ - String aclSetUser(String name, String... keys); + String aclSetUser(String name, String... rules); /** * Delete the specified user, from the ACL. * - * @param name The username to delete + * @param names The usernames to delete * @see ACL DELUSER * @return The number of users delete */ - long aclDelUser(String name); - - /** - * Delete the specified users, from the ACL. - * - * @param name The username to delete - * @param names Other usernames to delete - * @see ACL DELUSER - * @return The number of users delete - */ - long aclDelUser(String name, String... names); + long aclDelUser(String... names); /** * Show the available ACL categories. diff --git a/src/main/java/redis/clients/jedis/commands/ConfigCommands.java b/src/main/java/redis/clients/jedis/commands/ConfigCommands.java index 268205b1cba..3c099043da9 100644 --- a/src/main/java/redis/clients/jedis/commands/ConfigCommands.java +++ b/src/main/java/redis/clients/jedis/commands/ConfigCommands.java @@ -1,6 +1,6 @@ package redis.clients.jedis.commands; -import java.util.List; +import java.util.Map; /** * The interface about managing configuration parameters of Redis server. @@ -13,7 +13,7 @@ public interface ConfigCommands { * @param pattern name of Redis server's configuration * @return config value of Redis server */ - List configGet(String pattern); + Map configGet(String pattern); /** * Used to read the configuration parameters of Redis server. @@ -21,7 +21,7 @@ public interface ConfigCommands { * @param patterns names of Redis server's configuration * @return values of Redis server's configuration */ - List configGet(String... patterns); + Map configGet(String... patterns); /** * Used to read the configuration parameters of Redis server. @@ -29,7 +29,7 @@ public interface ConfigCommands { * @param pattern name of Redis server's configuration * @return value of Redis server's configuration */ - List configGet(byte[] pattern); + Map configGet(byte[] pattern); /** * Used to read the configuration parameters of Redis server. @@ -37,7 +37,7 @@ public interface ConfigCommands { * @param patterns names of Redis server's configuration * @return values of Redis server's configuration */ - List configGet(byte[]... patterns); + Map configGet(byte[]... patterns); /** * Used in order to reconfigure the Redis server at run time without @@ -52,6 +52,8 @@ public interface ConfigCommands { String configSet(String... parameterValues); + String configSet(Map parameterValues); + /** * Used in order to reconfigure the Redis server at run time without * the need to restart. @@ -65,6 +67,8 @@ public interface ConfigCommands { String configSet(byte[]... parameterValues); + String configSetBinary(Map parameterValues); + /** * Resets the statistics reported by Redis using the INFO command. *

diff --git a/src/main/java/redis/clients/jedis/resps/AccessControlLogEntry.java b/src/main/java/redis/clients/jedis/resps/AccessControlLogEntry.java index d23b10acf9a..09ef3a43bb7 100644 --- a/src/main/java/redis/clients/jedis/resps/AccessControlLogEntry.java +++ b/src/main/java/redis/clients/jedis/resps/AccessControlLogEntry.java @@ -9,6 +9,7 @@ * can be access via getters. For future purpose there is also {@link #getlogEntry} method that * returns a generic {@code Map} - in case where more info is returned from a server */ +// TODO: remove public class AccessControlLogEntry implements Serializable { private static final long serialVersionUID = 1L; diff --git a/src/main/java/redis/clients/jedis/resps/AccessControlUser.java b/src/main/java/redis/clients/jedis/resps/AccessControlUser.java index 6013a8f760b..2c9d0f9e786 100644 --- a/src/main/java/redis/clients/jedis/resps/AccessControlUser.java +++ b/src/main/java/redis/clients/jedis/resps/AccessControlUser.java @@ -1,75 +1,116 @@ package redis.clients.jedis.resps; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; +import java.util.StringJoiner; +// TODO: remove public class AccessControlUser { - private final List flags = new ArrayList<>(); - private final List keys = new ArrayList<>(); - private final List passwords = new ArrayList<>(); - private final List channels = new ArrayList<>(); - private String commands; + private final Map userInfo; + private final List flags; + private final List passwords; + private final String commands; + private final List keysList; + private final String keys; + private final List channelsList; + private final String channels; + private final List selectors; + + public AccessControlUser(Map map) { + this.userInfo = map; + + this.flags = (List) map.get("flags"); + + this.passwords = (List) map.get("passwords"); + + this.commands = (String) map.get("commands"); + + Object localKeys = map.get("keys"); + if (localKeys == null) { + this.keys = null; + this.keysList = null; + } else if (localKeys instanceof List) { + this.keysList = (List) localKeys; + this.keys = joinStrings(this.keysList); + } else { + this.keys = (String) localKeys; + this.keysList = Arrays.asList(this.keys.split(" ")); + } + + Object localChannels = map.get("channels"); + if (localChannels == null) { + this.channels = null; + this.channelsList = null; + } else if (localChannels instanceof List) { + this.channelsList = (List) localChannels; + this.channels = joinStrings(this.channelsList); + } else { + this.channels = (String) localChannels; + this.channelsList = Arrays.asList(this.channels.split(" ")); + } - public AccessControlUser() { + this.selectors = (List) map.get("selectors"); } - public void addFlag(String flag) { - flags.add(flag); + private static String joinStrings(List list) { + StringJoiner joiner = new StringJoiner(" "); + list.forEach(s -> joiner.add(s)); + return joiner.toString(); } public List getFlags() { return flags; } - public void addKey(String key) { - keys.add(key); - } - - public List getKeys() { - return keys; + /** + * @deprecated Use {@link AccessControlUser#getPasswords()}. + */ + @Deprecated + public List getPassword() { + return passwords; } - public void addKeys(String keys) { - if (!keys.isEmpty()) { - this.keys.addAll(Arrays.asList(keys.split(" "))); - } + public List getPasswords() { + return passwords; } - public void addPassword(String password) { - passwords.add(password); + public String getCommands() { + return commands; } - public List getPassword() { - return passwords; + /** + * @return Generic map containing all key-value pairs returned by the server + */ + public Map getUserInfo() { + return userInfo; } - public void addChannel(String channel) { - channels.add(channel); + public String getKeys() { + return keys; } - public List getChannels() { - return channels; + public List getKeysList() { + return keysList; } - public void addChannels(String channels) { - if (!channels.isEmpty()) { - this.channels.addAll(Arrays.asList(channels.split(" "))); - } + public List getChannelsList() { + return channelsList; } - public String getCommands() { - return commands; + public String getChannels() { + return channels; } - public void setCommands(String commands) { - this.commands = commands; + public List getSelectors() { + return selectors; } @Override public String toString() { return "AccessControlUser{" + "flags=" + flags + ", passwords=" + passwords - + ", commands='" + commands + "', keys='" + keys + "', channels='" + channels + "'}"; + + ", commands='" + commands + "', keys='" + keys + "', channels='" + channels + + "', selectors=" + selectors + "}"; } } diff --git a/src/main/java/redis/clients/jedis/resps/CommandDocument.java b/src/main/java/redis/clients/jedis/resps/CommandDocument.java index 219397811ea..3e320d8deca 100644 --- a/src/main/java/redis/clients/jedis/resps/CommandDocument.java +++ b/src/main/java/redis/clients/jedis/resps/CommandDocument.java @@ -5,21 +5,55 @@ import static redis.clients.jedis.BuilderFactory.STRING; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import redis.clients.jedis.util.KeyValue; public class CommandDocument { + + private static final String SUMMARY_STR = "summary"; + private static final String SINCE_STR = "since"; + private static final String GROUP_STR = "group"; + private static final String COMPLEXITY_STR = "complexity"; + private static final String HISTORY_STR = "history"; + private final String summary; private final String since; private final String group; private final String complexity; private final List history; + @Deprecated public CommandDocument(String summary, String since, String group, String complexity, List history) { this.summary = summary; this.since = since; this.group = group; this.complexity = complexity; - this.history = history; + this.history = (List) history; + } + + public CommandDocument(Map map) { + this.summary = (String) map.get(SUMMARY_STR); + this.since = (String) map.get(SINCE_STR); + this.group = (String) map.get(GROUP_STR); + this.complexity = (String) map.get(COMPLEXITY_STR); + + List historyObject = (List) map.get(HISTORY_STR); + if (historyObject == null) { + this.history = null; + } else if (historyObject.isEmpty()) { + this.history = Collections.emptyList(); + } else if (historyObject.get(0) instanceof KeyValue) { + this.history = historyObject.stream().map(o -> (KeyValue) o) + .map(kv -> (String) kv.getKey() + ": " + (String) kv.getValue()) + .collect(Collectors.toList()); + } else { + this.history = historyObject.stream().map(o -> (List) o) + .map(l -> (String) l.get(0) + ": " + (String) l.get(1)) + .collect(Collectors.toList()); + } } public String getSummary() { @@ -42,6 +76,7 @@ public List getHistory() { return history; } + @Deprecated public static final Builder COMMAND_DOCUMENT_BUILDER = new Builder() { @Override public CommandDocument build(Object data) { diff --git a/src/main/java/redis/clients/jedis/resps/FunctionStats.java b/src/main/java/redis/clients/jedis/resps/FunctionStats.java index 917af0ce684..b8d55c181f4 100644 --- a/src/main/java/redis/clients/jedis/resps/FunctionStats.java +++ b/src/main/java/redis/clients/jedis/resps/FunctionStats.java @@ -5,6 +5,7 @@ import java.util.Map; import redis.clients.jedis.Builder; import redis.clients.jedis.BuilderFactory; +import redis.clients.jedis.util.KeyValue; public class FunctionStats { @@ -28,12 +29,38 @@ public Map> getEngines() { @Override public FunctionStats build(Object data) { - List superMapList = (List) data; + if (data == null) return null; + List list = (List) data; + if (list.isEmpty()) return null; - Map runningScriptMap = superMapList.get(1) == null ? null - : BuilderFactory.ENCODED_OBJECT_MAP.build(superMapList.get(1)); + if (list.get(0) instanceof KeyValue) { - List enginesList = (List) superMapList.get(3); + Map runningScriptMap = null; + Map> enginesMap = null; + + for (KeyValue kv : (List) list) { + switch (BuilderFactory.STRING.build(kv.getKey())) { + case "running_script": + runningScriptMap = BuilderFactory.ENCODED_OBJECT_MAP.build(kv.getValue()); + break; + case "engines": + List ilist = (List) kv.getValue(); + enginesMap = new LinkedHashMap<>(ilist.size()); + for (KeyValue ikv : (List) kv.getValue()) { + enginesMap.put(BuilderFactory.STRING.build(ikv.getKey()), + BuilderFactory.ENCODED_OBJECT_MAP.build(ikv.getValue())); + } + break; + } + } + + return new FunctionStats(runningScriptMap, enginesMap); + } + + Map runningScriptMap = list.get(1) == null ? null + : BuilderFactory.ENCODED_OBJECT_MAP.build(list.get(1)); + + List enginesList = (List) list.get(3); Map> enginesMap = new LinkedHashMap<>(enginesList.size() / 2); for (int i = 0; i < enginesList.size(); i += 2) { diff --git a/src/main/java/redis/clients/jedis/resps/LibraryInfo.java b/src/main/java/redis/clients/jedis/resps/LibraryInfo.java index 7934ce7080b..41ddfc7b624 100644 --- a/src/main/java/redis/clients/jedis/resps/LibraryInfo.java +++ b/src/main/java/redis/clients/jedis/resps/LibraryInfo.java @@ -8,7 +8,12 @@ import java.util.stream.Collectors; import redis.clients.jedis.Builder; +import redis.clients.jedis.BuilderFactory; +import redis.clients.jedis.util.KeyValue; +import redis.clients.jedis.util.SafeEncoder; +//[library_name=mylib, engine=LUA, functions=[[name=myfunc, description=null, flags=[]]], library_code=#!LUA name=mylib +// redis.register_function('myfunc', function(keys, args) return args[1] end)] public class LibraryInfo { private final String libraryName; @@ -46,15 +51,40 @@ public String getLibraryCode() { public static final Builder LIBRARY_BUILDER = new Builder() { @Override public LibraryInfo build(Object data) { - List objectList = (List) data; - String libname = STRING.build(objectList.get(1)); - String engine = STRING.build(objectList.get(3)); - List rawFunctions = (List) objectList.get(5); + if (data == null) return null; + List list = (List) data; + if (list.isEmpty()) return null; + + if (list.get(0) instanceof KeyValue) { + String libname = null, enginename = null, librarycode = null; + List> functions = null; + for (KeyValue kv : (List) list) { + switch (BuilderFactory.STRING.build(kv.getKey())) { + case "library_name": + libname = BuilderFactory.STRING.build(kv.getValue()); + break; + case "engine": + enginename = BuilderFactory.STRING.build(kv.getValue()); + break; + case "functions": + functions = ((List) kv.getValue()).stream().map(o -> ENCODED_OBJECT_MAP.build(o)).collect(Collectors.toList()); + break; + case "library_code": + librarycode = BuilderFactory.STRING.build(kv.getValue()); + break; + } + } + return new LibraryInfo(libname, enginename, functions, librarycode); + } + + String libname = STRING.build(list.get(1)); + String engine = STRING.build(list.get(3)); + List rawFunctions = (List) list.get(5); List> functions = rawFunctions.stream().map(o -> ENCODED_OBJECT_MAP.build(o)).collect(Collectors.toList()); - if (objectList.size() <= 6) { + if (list.size() <= 6) { return new LibraryInfo(libname, engine, functions); } - String code = STRING.build(objectList.get(7)); + String code = STRING.build(list.get(7)); return new LibraryInfo(libname, engine, functions, code); } }; diff --git a/src/main/java/redis/clients/jedis/resps/Slowlog.java b/src/main/java/redis/clients/jedis/resps/Slowlog.java index 13898af98df..58ccf53e218 100644 --- a/src/main/java/redis/clients/jedis/resps/Slowlog.java +++ b/src/main/java/redis/clients/jedis/resps/Slowlog.java @@ -2,7 +2,7 @@ import java.util.ArrayList; import java.util.List; - +import redis.clients.jedis.BuilderFactory; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.util.SafeEncoder; @@ -19,17 +19,11 @@ public class Slowlog { @SuppressWarnings("unchecked") private Slowlog(List properties) { - super(); this.id = (Long) properties.get(0); this.timeStamp = (Long) properties.get(1); this.executionTime = (Long) properties.get(2); - List bargs = (List) properties.get(3); - this.args = new ArrayList<>(bargs.size()); - - for (byte[] barg : bargs) { - this.args.add(SafeEncoder.encode(barg)); - } + this.args = BuilderFactory.STRING_LIST.build(properties.get(3)); if (properties.size() == 4) return; this.clientIpPort = HostAndPort.from(SafeEncoder.encode((byte[]) properties.get(4))); @@ -43,7 +37,6 @@ public static List from(List nestedMultiBulkReply) { List properties = (List) obj; logs.add(new Slowlog(properties)); } - return logs; } diff --git a/src/main/java/redis/clients/jedis/util/SafeEncoder.java b/src/main/java/redis/clients/jedis/util/SafeEncoder.java index 314d7218517..fb5d8fb24e0 100644 --- a/src/main/java/redis/clients/jedis/util/SafeEncoder.java +++ b/src/main/java/redis/clients/jedis/util/SafeEncoder.java @@ -46,6 +46,11 @@ public static Object encodeObject(Object dataToEncode) { return SafeEncoder.encode((byte[]) dataToEncode); } + if (dataToEncode instanceof KeyValue) { + KeyValue keyValue = (KeyValue) dataToEncode; + return new KeyValue<>(encodeObject(keyValue.getKey()), encodeObject(keyValue.getValue())); + } + if (dataToEncode instanceof List) { List arrayToDecode = (List) dataToEncode; List returnValueArray = new ArrayList(arrayToDecode.size()); diff --git a/src/test/java/redis/clients/jedis/commands/jedis/AccessControlListCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/AccessControlListCommandsTest.java index 777f8badac7..9d4f3c65684 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/AccessControlListCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/AccessControlListCommandsTest.java @@ -4,6 +4,7 @@ import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.endsWith; import static org.hamcrest.Matchers.startsWith; + import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -13,7 +14,6 @@ import java.util.Arrays; import java.util.List; -import org.hamcrest.CoreMatchers; import org.hamcrest.Matchers; import org.junit.After; import org.junit.BeforeClass; @@ -88,7 +88,7 @@ public void addAndRemoveUser() { public void aclUsers() { List users = jedis.aclUsers(); assertEquals(2, users.size()); - assertThat(users, CoreMatchers.hasItem("default")); + assertThat(users, Matchers.hasItem("default")); assertEquals(2, jedis.aclUsersBinary().size()); // Test binary } @@ -101,7 +101,7 @@ public void aclGetUser() { assertFalse(userInfo.getFlags().isEmpty()); assertEquals(1, userInfo.getPassword().size()); assertEquals("+@all", userInfo.getCommands()); - assertEquals("~*", userInfo.getKeys().get(0)); + assertEquals("~*", userInfo.getKeys()); // create new user jedis.aclSetUser(USER_NAME); @@ -504,7 +504,7 @@ public void aclBinaryCommandsTest() { assertThat(userInfo.getCommands(), containsString("+@all")); assertThat(userInfo.getCommands(), containsString("-@string")); assertThat(userInfo.getCommands(), containsString("+debug|digest")); - assertEquals("&testchannel:*", userInfo.getChannels().get(0)); + assertEquals("&testchannel:*", userInfo.getChannels()); jedis.aclDelUser(USER_NAME.getBytes()); diff --git a/src/test/java/redis/clients/jedis/commands/jedis/AllKindOfValuesCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/AllKindOfValuesCommandsTest.java index 48e8d389421..31e745bdd15 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/AllKindOfValuesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/AllKindOfValuesCommandsTest.java @@ -1,5 +1,6 @@ package redis.clients.jedis.commands.jedis; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.*; import static redis.clients.jedis.Protocol.Command.BLPOP; @@ -14,6 +15,7 @@ import static redis.clients.jedis.params.ScanParams.SCAN_POINTER_START_BINARY; import java.util.*; +import org.hamcrest.Matchers; import org.junit.Test; import redis.clients.jedis.HostAndPort; @@ -25,10 +27,12 @@ import redis.clients.jedis.args.FlushMode; import redis.clients.jedis.params.RestoreParams; import redis.clients.jedis.HostAndPorts; +import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.util.SafeEncoder; import redis.clients.jedis.exceptions.JedisDataException; import redis.clients.jedis.params.SetParams; import redis.clients.jedis.util.AssertUtil; +import redis.clients.jedis.util.KeyValue; public class AllKindOfValuesCommandsTest extends JedisCommandsTestBase { final byte[] bfoo = { 0x01, 0x02, 0x03, 0x04 }; @@ -971,37 +975,74 @@ public void sendBlockingCommandTest() { } @Test - public void encodeCompleteResponse() { + public void encodeCompleteResponsePing() { + assertEquals("PONG", SafeEncoder.encodeObject(jedis.sendCommand(PING))); + } + + @Test + public void encodeCompleteResponseHgetall() { + HashMap entries = new HashMap<>(); + entries.put("foo", "bar"); + entries.put("foo2", "bar2"); + jedis.hset("hash:test:encode", entries); + + if (protocol != RedisProtocol.RESP3) { + List encodeObj = (List) SafeEncoder.encodeObject(jedis.sendCommand(HGETALL, "hash:test:encode")); + + assertEquals(4, encodeObj.size()); + entries.forEach((k, v) -> { + assertThat((Iterable) encodeObj, Matchers.hasItem(k)); + assertEquals(v, findValueFromMapAsList(encodeObj, k)); + }); + } else { + List encodeObj = (List) SafeEncoder.encodeObject(jedis.sendCommand(HGETALL, "hash:test:encode")); + + assertEquals(2, encodeObj.size()); + encodeObj.forEach(kv -> { + assertThat(entries, Matchers.hasEntry(kv.getKey(), kv.getValue())); + }); + } + } + + @Test + public void encodeCompleteResponseXinfoStream() { HashMap entry = new HashMap<>(); entry.put("foo", "bar"); StreamEntryID entryID = jedis.xadd("mystream", StreamEntryID.NEW_ENTRY, entry); jedis.xgroupCreate("mystream", "mygroup", null, false); Object obj = jedis.sendCommand(XINFO, "STREAM", "mystream"); - List encodeObj = (List) SafeEncoder.encodeObject(obj); - assertTrue(encodeObj.size() >= 14); - assertEquals(0, encodeObj.size() % 2); // must be even + if (protocol != RedisProtocol.RESP3) { + List encodeObj = (List) SafeEncoder.encodeObject(obj); + + assertThat(encodeObj.size(), Matchers.greaterThanOrEqualTo(14)); + assertEquals("must have even number of elements", 0, encodeObj.size() % 2); // must be even - assertEquals(1L, findValueFromMapAsList(encodeObj, "length")); - assertEquals(entryID.toString(), findValueFromMapAsList(encodeObj, "last-generated-id")); + assertEquals(1L, findValueFromMapAsList(encodeObj, "length")); + assertEquals(entryID.toString(), findValueFromMapAsList(encodeObj, "last-generated-id")); - List entryAsList = new ArrayList<>(2); - entryAsList.add("foo"); - entryAsList.add("bar"); + List entryAsList = new ArrayList<>(2); + entryAsList.add("foo"); + entryAsList.add("bar"); - assertEquals(entryAsList, ((List) findValueFromMapAsList(encodeObj, "first-entry")).get(1)); - assertEquals(entryAsList, ((List) findValueFromMapAsList(encodeObj, "last-entry")).get(1)); + assertEquals(entryAsList, ((List) findValueFromMapAsList(encodeObj, "first-entry")).get(1)); + assertEquals(entryAsList, ((List) findValueFromMapAsList(encodeObj, "last-entry")).get(1)); + } else { + List encodeObj = (List) SafeEncoder.encodeObject(obj); - assertEquals("PONG", SafeEncoder.encodeObject(jedis.sendCommand(PING))); + assertThat(encodeObj.size(), Matchers.greaterThanOrEqualTo(7)); - entry.put("foo2", "bar2"); - jedis.hset("hash:test:encode", entry); - encodeObj = (List) SafeEncoder.encodeObject(jedis.sendCommand(HGETALL, "hash:test:encode")); + assertEquals(1L, findValueFromMapAsKeyValueList(encodeObj, "length")); + assertEquals(entryID.toString(), findValueFromMapAsKeyValueList(encodeObj, "last-generated-id")); - assertEquals(4, encodeObj.size()); - assertTrue(encodeObj.contains("foo")); - assertTrue(encodeObj.contains("foo2")); + List entryAsList = new ArrayList<>(2); + entryAsList.add("foo"); + entryAsList.add("bar"); + + assertEquals(entryAsList, ((List) findValueFromMapAsKeyValueList(encodeObj, "first-entry")).get(1)); + assertEquals(entryAsList, ((List) findValueFromMapAsKeyValueList(encodeObj, "last-entry")).get(1)); + } } private Object findValueFromMapAsList(List list, Object key) { @@ -1013,6 +1054,15 @@ private Object findValueFromMapAsList(List list, Object key) { return null; } + private Object findValueFromMapAsKeyValueList(List list, Object key) { + for (KeyValue kv : list) { + if (key.equals(kv.getKey())) { + return kv.getValue(); + } + } + return null; + } + @Test public void copy() { assertFalse(jedis.copy("unknown", "foo", false)); diff --git a/src/test/java/redis/clients/jedis/commands/jedis/ControlCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/ControlCommandsTest.java index d97614cc32d..df3fef6886f 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/ControlCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/ControlCommandsTest.java @@ -207,21 +207,23 @@ public void onCommand(String command) { @Test public void configGet() { - List info = jedis.configGet("m*"); + Map info = jedis.configGet("m*"); assertNotNull(info); assertFalse(info.isEmpty()); - assertTrue(info.size() % 2 == 0); - List infoBinary = jedis.configGet("m*".getBytes()); +// assertTrue(info.size() % 2 == 0); + Map infoBinary = jedis.configGet("m*".getBytes()); assertNotNull(infoBinary); assertFalse(infoBinary.isEmpty()); - assertTrue(infoBinary.size() % 2 == 0); +// assertTrue(infoBinary.size() % 2 == 0); } @Test public void configSet() { - List info = jedis.configGet("maxmemory"); - assertEquals("maxmemory", info.get(0)); - String memory = info.get(1); + Map info = jedis.configGet("maxmemory"); +// assertEquals("maxmemory", info.get(0)); +// String memory = info.get(1); + String memory = info.get("maxmemory"); + assertNotNull(memory); assertEquals("OK", jedis.configSet("maxmemory", "200")); assertEquals("OK", jedis.configSet("maxmemory", memory)); } @@ -229,9 +231,11 @@ public void configSet() { @Test public void configSetBinary() { byte[] maxmemory = SafeEncoder.encode("maxmemory"); - List info = jedis.configGet(maxmemory); - assertArrayEquals(maxmemory, info.get(0)); - byte[] memory = info.get(1); + Map info = jedis.configGet(maxmemory); +// assertArrayEquals(maxmemory, info.get(0)); +// byte[] memory = info.get(1); + byte[] memory = info.get(maxmemory); + assertNotNull(memory); assertEquals("OK", jedis.configSet(maxmemory, Protocol.toByteArray(200))); assertEquals("OK", jedis.configSet(maxmemory, memory)); } @@ -239,15 +243,15 @@ public void configSetBinary() { @Test public void configGetSetMulti() { String[] params = new String[]{"hash-max-listpack-entries", "set-max-intset-entries", "zset-max-listpack-entries"}; - List info = jedis.configGet(params); - assertEquals(6, info.size()); - assertEquals("OK", jedis.configSet(info.toArray(new String[6]))); + Map info = jedis.configGet(params); + assertEquals(3, info.size()); + assertEquals("OK", jedis.configSet(info)); byte[][] bparams = new byte[][]{SafeEncoder.encode("hash-max-listpack-entries"), SafeEncoder.encode("set-max-intset-entries"), SafeEncoder.encode("zset-max-listpack-entries")}; - List binfo = jedis.configGet(bparams); - assertEquals(6, binfo.size()); - assertEquals("OK", jedis.configSet(binfo.toArray(new byte[6][]))); + Map binfo = jedis.configGet(bparams); + assertEquals(3, binfo.size()); + assertEquals("OK", jedis.configSetBinary(binfo)); } @Test diff --git a/src/test/java/redis/clients/jedis/commands/jedis/JedisCommandsTestBase.java b/src/test/java/redis/clients/jedis/commands/jedis/JedisCommandsTestBase.java index 1a7f3a876c9..262eed88cc6 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/JedisCommandsTestBase.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/JedisCommandsTestBase.java @@ -7,11 +7,13 @@ import redis.clients.jedis.HostAndPort; import redis.clients.jedis.Jedis; import redis.clients.jedis.HostAndPorts; +import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.util.RedisProtocolUtil; public abstract class JedisCommandsTestBase { protected static final HostAndPort hnp = HostAndPorts.getRedisServers().get(0); + protected static final RedisProtocol protocol = RedisProtocolUtil.getRedisProtocol(); protected Jedis jedis; @@ -23,8 +25,7 @@ public JedisCommandsTestBase() { public void setUp() throws Exception { // jedis = new Jedis(hnp, DefaultJedisClientConfig.builder().timeoutMillis(500).password("foobared").build()); jedis = new Jedis(hnp, DefaultJedisClientConfig.builder() - .protocol(RedisProtocolUtil.getRedisProtocol()) - .timeoutMillis(500).password("foobared").build()); + .protocol(protocol).timeoutMillis(500).password("foobared").build()); jedis.flushAll(); } @@ -36,7 +37,6 @@ public void tearDown() throws Exception { protected Jedis createJedis() { // return new Jedis(hnp, DefaultJedisClientConfig.builder().password("foobared").build()); return new Jedis(hnp, DefaultJedisClientConfig.builder() - .protocol(RedisProtocolUtil.getRedisProtocol()) - .password("foobared").build()); + .protocol(protocol).password("foobared").build()); } } diff --git a/src/test/java/redis/clients/jedis/commands/jedis/ModuleTest.java b/src/test/java/redis/clients/jedis/commands/jedis/ModuleTest.java index 8159f45d4a2..2538fc2f5fa 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/ModuleTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/ModuleTest.java @@ -3,6 +3,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import java.util.Collections; import java.util.List; import org.junit.Test; @@ -35,11 +36,12 @@ public void testModules() { List modules = jedis.moduleList(); assertEquals("testmodule", modules.get(0).getName()); + assertEquals("testmodule", modules.get(0).getInfo().get("name")); Object output = jedis.sendCommand(ModuleCommand.SIMPLE); assertTrue((Long) output > 0); assertEquals("OK", jedis.moduleUnload("testmodule")); - assertEquals(0, jedis.moduleList().size()); + assertEquals(Collections.emptyList(), jedis.moduleList()); } } diff --git a/src/test/java/redis/clients/jedis/commands/jedis/ScriptingCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/ScriptingCommandsTest.java index f21464ff776..9d2f01b457c 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/ScriptingCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/ScriptingCommandsTest.java @@ -14,6 +14,7 @@ import org.junit.Test; import redis.clients.jedis.Jedis; +import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.args.FlushMode; import redis.clients.jedis.args.FunctionRestorePolicy; import redis.clients.jedis.exceptions.JedisConnectionException; @@ -22,6 +23,7 @@ import redis.clients.jedis.resps.FunctionStats; import redis.clients.jedis.resps.LibraryInfo; import redis.clients.jedis.util.ClientKillerUtil; +import redis.clients.jedis.util.KeyValue; import redis.clients.jedis.util.SafeEncoder; public class ScriptingCommandsTest extends JedisCommandsTestBase { @@ -387,19 +389,37 @@ public void functionList() { assertEquals(functionCode, response.getLibraryCode()); // Binary - List bresponse = (List) jedis.functionListBinary().get(0); - assertArrayEquals(library.getBytes(), (byte[]) bresponse.get(1)); + if (protocol != RedisProtocol.RESP3) { - bresponse = (List) jedis.functionListWithCodeBinary().get(0); - assertArrayEquals(library.getBytes(), (byte[]) bresponse.get(1)); - assertNotNull(bresponse.get(7)); + List bresponse = (List) jedis.functionListBinary().get(0); + assertArrayEquals(library.getBytes(), (byte[]) bresponse.get(1)); - bresponse = (List) jedis.functionList(library.getBytes()).get(0); - assertArrayEquals(library.getBytes(), (byte[]) bresponse.get(1)); + bresponse = (List) jedis.functionListWithCodeBinary().get(0); + assertArrayEquals(library.getBytes(), (byte[]) bresponse.get(1)); + assertNotNull(bresponse.get(7)); - bresponse = (List) jedis.functionListWithCode(library.getBytes()).get(0); - assertArrayEquals(library.getBytes(), (byte[]) bresponse.get(1)); - assertNotNull(bresponse.get(7)); + bresponse = (List) jedis.functionList(library.getBytes()).get(0); + assertArrayEquals(library.getBytes(), (byte[]) bresponse.get(1)); + + bresponse = (List) jedis.functionListWithCode(library.getBytes()).get(0); + assertArrayEquals(library.getBytes(), (byte[]) bresponse.get(1)); + assertNotNull(bresponse.get(7)); + } else { + + List bresponse = (List) jedis.functionListBinary().get(0); + assertArrayEquals(library.getBytes(), (byte[]) bresponse.get(0).getValue()); + + bresponse = (List) jedis.functionListWithCodeBinary().get(0); + assertArrayEquals(library.getBytes(), (byte[]) bresponse.get(0).getValue()); + assertNotNull(bresponse.get(3)); + + bresponse = (List) jedis.functionList(library.getBytes()).get(0); + assertArrayEquals(library.getBytes(), (byte[]) bresponse.get(0).getValue()); + + bresponse = (List) jedis.functionListWithCode(library.getBytes()).get(0); + assertArrayEquals(library.getBytes(), (byte[]) bresponse.get(0).getValue()); + assertNotNull(bresponse.get(3)); + } } @Test diff --git a/src/test/java/redis/clients/jedis/commands/jedis/SlowlogCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/SlowlogCommandsTest.java index d9b3ba70ba9..66806b933ab 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/SlowlogCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/SlowlogCommandsTest.java @@ -1,12 +1,13 @@ package redis.clients.jedis.commands.jedis; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; import java.util.Arrays; import java.util.List; +import org.hamcrest.Matchers; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -28,7 +29,7 @@ public class SlowlogCommandsTest extends JedisCommandsTestBase { @Override public void setUp() throws Exception { super.setUp(); - slowlogTimeValue = jedis.configGet(SLOWLOG_TIME_PARAM).get(1); + slowlogTimeValue = jedis.configGet(SLOWLOG_TIME_PARAM).get(SLOWLOG_TIME_PARAM); } @After @@ -41,6 +42,8 @@ public void tearDown() throws Exception { @Test public void slowlog() { jedis.configSet(SLOWLOG_TIME_PARAM, ZERO_STRING); + jedis.slowlogReset(); + jedis.set("foo", "bar"); jedis.set("foo2", "bar2"); @@ -48,9 +51,9 @@ public void slowlog() { assertEquals(1, reducedLog.size()); Slowlog log = reducedLog.get(0); - assertTrue(log.getId() > 0); - assertTrue(log.getTimeStamp() > 0); - assertTrue(log.getExecutionTime() >= 0); + assertThat(log.getId(), Matchers.greaterThan(0L)); + assertThat(log.getTimeStamp(), Matchers.greaterThan(0L)); + assertThat(log.getExecutionTime(), Matchers.greaterThanOrEqualTo(0L)); assertNotNull(log.getArgs()); List breducedLog = jedis.slowlogGetBinary(1); @@ -63,8 +66,9 @@ public void slowlog() { assertNotNull(blog1); // assertEquals(7, jedis.slowlogLen()); - assertTrue(jedis.slowlogLen() > 5 && jedis.slowlogLen() < 12); - assertTrue(jedis.slowlogGet().toString().contains("SLOWLOG")); + assertThat(jedis.slowlogLen(), + Matchers.allOf(Matchers.greaterThanOrEqualTo(6L), Matchers.lessThanOrEqualTo(13L))); + assertThat(jedis.slowlogGet().toString(), Matchers.containsString("SLOWLOG")); } @Test @@ -74,36 +78,37 @@ public void slowlogObjectDetails() { jedis.slowlogReset(); jedis.configSet(SLOWLOG_TIME_PARAM, ZERO_STRING); - List logs = jedis.slowlogGet(); // Get only 'CONFIG SET' - assertEquals(1, logs.size()); + List logs = jedis.slowlogGet(); // Get only 'CONFIG SET', or including 'SLOWLOG RESET' + //assertEquals(1, logs.size()); + assertThat(logs.size(), Matchers.allOf(Matchers.greaterThanOrEqualTo(1), Matchers.lessThanOrEqualTo(2))); Slowlog log = logs.get(0); - assertTrue(log.getId() > 0); - assertTrue(log.getTimeStamp() > 0); - assertTrue(log.getExecutionTime() > 0); + assertThat(log.getId(), Matchers.greaterThan(0L)); + assertThat(log.getTimeStamp(), Matchers.greaterThan(0L)); + assertThat(log.getExecutionTime(), Matchers.greaterThan(0L)); assertEquals(4, log.getArgs().size()); assertEquals(SafeEncoder.encode(Protocol.Command.CONFIG.getRaw()), log.getArgs().get(0)); assertEquals(SafeEncoder.encode(Protocol.Keyword.SET.getRaw()), log.getArgs().get(1)); assertEquals(SLOWLOG_TIME_PARAM, log.getArgs().get(2)); assertEquals(ZERO_STRING, log.getArgs().get(3)); -// assertEquals("127.0.0.1", log.getClientIpPort().getHost()); - assertTrue(LOCAL_IPS.contains(log.getClientIpPort().getHost())); - assertTrue(log.getClientIpPort().getPort() > 0); + assertThat(log.getClientIpPort().getHost(), Matchers.in(LOCAL_IPS)); + assertThat(log.getClientIpPort().getPort(), Matchers.greaterThan(0)); assertEquals(clientName, log.getClientName()); } @Test - public void slowlogBinaryDetails() { + public void slowlogBinaryObjectDetails() { final byte[] clientName = SafeEncoder.encode("slowlog-binary-client"); jedis.clientSetname(clientName); jedis.slowlogReset(); jedis.configSet(SafeEncoder.encode(SLOWLOG_TIME_PARAM), SafeEncoder.encode(ZERO_STRING)); - List logs = jedis.slowlogGetBinary(); // Get only 'CONFIG SET' - assertEquals(1, logs.size()); + List logs = jedis.slowlogGetBinary(); // Get only 'CONFIG SET', or including 'SLOWLOG RESET' + //assertEquals(1, logs.size()); + assertThat(logs.size(), Matchers.allOf(Matchers.greaterThanOrEqualTo(1), Matchers.lessThanOrEqualTo(2))); List log = (List) logs.get(0); - assertTrue((Long) log.get(0) > 0); - assertTrue((Long) log.get(1) > 0); - assertTrue((Long) log.get(2) > 0); + assertThat((Long) log.get(0), Matchers.greaterThan(0L)); + assertThat((Long) log.get(1), Matchers.greaterThan(0L)); + assertThat((Long) log.get(2), Matchers.greaterThan(0L)); List args = (List) log.get(3); assertEquals(4, args.size()); assertArrayEquals(Protocol.Command.CONFIG.getRaw(), (byte[]) args.get(0)); @@ -111,7 +116,7 @@ public void slowlogBinaryDetails() { assertArrayEquals(SafeEncoder.encode(SLOWLOG_TIME_PARAM), (byte[]) args.get(2)); assertArrayEquals(Protocol.toByteArray(0), (byte[]) args.get(3)); // assertTrue(SafeEncoder.encode((byte[]) log.get(4)).startsWith("127.0.0.1:")); - assertTrue(((byte[]) log.get(4)).length > 0); + assertThat(((byte[]) log.get(4)).length, Matchers.greaterThanOrEqualTo(10)); // 'IP:PORT' assertArrayEquals(clientName, (byte[]) log.get(5)); } } diff --git a/src/test/java/redis/clients/jedis/commands/jedis/StreamsCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/StreamsCommandsTest.java index 6713fb3428c..6b28f9ed19f 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/StreamsCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/StreamsCommandsTest.java @@ -500,7 +500,7 @@ public void xreadGroupWithParamsWhenPendingMessageIsDiscarded() { @Test public void xack() { - Map map = new HashMap(); + Map map = new HashMap<>(); map.put("f1", "v1"); jedis.xadd("xack-stream", (StreamEntryID) null, map); diff --git a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledCommandsTestHelper.java b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledCommandsTestHelper.java index 42a1e20b79c..0b8f3b9ca10 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledCommandsTestHelper.java +++ b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledCommandsTestHelper.java @@ -5,11 +5,13 @@ import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPooled; import redis.clients.jedis.HostAndPorts; +import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.util.RedisProtocolUtil; public class PooledCommandsTestHelper { private static final HostAndPort nodeInfo = HostAndPorts.getRedisServers().get(0); + private static final RedisProtocol protocol = RedisProtocolUtil.getRedisProtocol(); private static Jedis node; @@ -21,7 +23,7 @@ static JedisPooled getPooled() throws InterruptedException { //return new JedisPooled(nodeInfo.getHost(), nodeInfo.getPort(), null, "foobared"); return new JedisPooled(nodeInfo, DefaultJedisClientConfig.builder() - .protocol(RedisProtocolUtil.getRedisProtocol()).password("foobared").build()); + .protocol(protocol).password("foobared").build()); } static void clearData() { From 7b570aeed7811f1b0eb67e17a9caa3302c863029 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Mon, 5 Jun 2023 00:41:00 +0600 Subject: [PATCH 02/10] module replies --- .../redis/clients/jedis/BuilderFactory.java | 15 -------- .../clients/jedis/timeseries/TSInfo.java | 37 +++++++++++-------- .../timeseries/TimeSeriesBuilderFactory.java | 36 +++++++++--------- 3 files changed, 39 insertions(+), 49 deletions(-) diff --git a/src/main/java/redis/clients/jedis/BuilderFactory.java b/src/main/java/redis/clients/jedis/BuilderFactory.java index 3cf42e65f13..7ddb8e1da2f 100644 --- a/src/main/java/redis/clients/jedis/BuilderFactory.java +++ b/src/main/java/redis/clients/jedis/BuilderFactory.java @@ -1718,21 +1718,6 @@ public String toString() { } }; - public static final Builder> ENCODED_OBJECT_MAP_FROM_PAIRS = new Builder>() { - @Override - public Map build(Object data) { - final List list = (List) data; - final Map map = new HashMap<>(list.size(), 1f); - for (Object object : list) { - if (object == null) continue; - final List flat = (List) object; - if (flat.isEmpty()) continue; - map.put(STRING.build(flat.get(0)), ENCODED_OBJECT.build(flat.get(1))); - } - return map; - } - }; - public static final Builder> LIBRARY_LIST = new Builder>() { @Override public List build(Object data) { diff --git a/src/main/java/redis/clients/jedis/timeseries/TSInfo.java b/src/main/java/redis/clients/jedis/timeseries/TSInfo.java index b77743fdce5..3eb878aed8b 100644 --- a/src/main/java/redis/clients/jedis/timeseries/TSInfo.java +++ b/src/main/java/redis/clients/jedis/timeseries/TSInfo.java @@ -2,13 +2,13 @@ import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import redis.clients.jedis.Builder; import redis.clients.jedis.BuilderFactory; import redis.clients.jedis.util.DoublePrecision; +import redis.clients.jedis.util.KeyValue; import redis.clients.jedis.util.SafeEncoder; public class TSInfo { @@ -127,19 +127,18 @@ public TSInfo build(Object data) { } }; - // TODO: unify INFO builders public static Builder TIMESERIES_INFO_RESP3 = new Builder() { @Override public TSInfo build(Object data) { - List list = (List) data; + List list = (List) data; Map properties = new HashMap<>(); Map labels = null; Map rules = null; List> chunks = null; - for (int i = 0; i < list.size(); i += 2) { - String prop = SafeEncoder.encode((byte[]) list.get(i)); - Object value = list.get(i + 1); + for (KeyValue kv : list) { + String prop = BuilderFactory.STRING.build(kv.getKey()); + Object value = kv.getValue(); if (value instanceof List) { switch (prop) { case LABELS_PROPERTY: @@ -147,24 +146,30 @@ public TSInfo build(Object data) { value = labels; break; case RULES_PROPERTY: - List rulesDataList = (List) value; - Map> rulesValueMap = new HashMap<>(rulesDataList.size() / 2, 1f); + List rulesDataList = (List) value; + Map> rulesValueMap = new HashMap<>(rulesDataList.size(), 1f); rules = new HashMap<>(rulesDataList.size()); - for (Iterator iterator = rulesDataList.iterator(); iterator.hasNext();) { - String ruleName = BuilderFactory.STRING.build(iterator.next()); - List ruleValueList = BuilderFactory.ENCODED_OBJECT_LIST.build(iterator.next()); + for (KeyValue rkv : rulesDataList) { + String ruleName = BuilderFactory.STRING.build(rkv.getKey()); + List ruleValueList = BuilderFactory.ENCODED_OBJECT_LIST.build(rkv.getValue()); rulesValueMap.put(ruleName, ruleValueList); rules.put(ruleName, new Rule(ruleName, ruleValueList)); } value = rulesValueMap; break; case CHUNKS_PROPERTY: - List chunksDataList = (List) value; + List>> chunksDataList = (List>>) value; List> chunksValueList = new ArrayList<>(chunksDataList.size()); chunks = new ArrayList<>(chunksDataList.size()); - for (Object chunkData : chunksDataList) { - Map chunk = BuilderFactory.ENCODED_OBJECT_MAP_FROM_PAIRS.build(chunkData); - chunksValueList.add(new HashMap<>(chunk)); + for (List> chunkDataAsList : chunksDataList) { + Map chunk = new HashMap<>(); + for (List chunkDataInnerList : chunkDataAsList) { + for (Object chunkDataInnerInnerObject : chunkDataInnerList) { + KeyValue cikv = (KeyValue) chunkDataInnerInnerObject; + chunk.put(BuilderFactory.STRING.build(cikv.getKey()), BuilderFactory.ENCODED_OBJECT.build(cikv.getValue())); + } + } + chunksValueList.add(chunk); chunks.add(chunk); } value = chunksValueList; @@ -174,7 +179,7 @@ public TSInfo build(Object data) { break; } } else if (value instanceof byte[]) { - value = SafeEncoder.encode((byte[]) value); + value = BuilderFactory.STRING.build(value); if (DUPLICATE_POLICY_PROPERTY.equals(prop)) { try { value = DuplicatePolicy.valueOf(((String) value).toUpperCase()); diff --git a/src/main/java/redis/clients/jedis/timeseries/TimeSeriesBuilderFactory.java b/src/main/java/redis/clients/jedis/timeseries/TimeSeriesBuilderFactory.java index 0b90d4328ec..96e40d57691 100644 --- a/src/main/java/redis/clients/jedis/timeseries/TimeSeriesBuilderFactory.java +++ b/src/main/java/redis/clients/jedis/timeseries/TimeSeriesBuilderFactory.java @@ -1,6 +1,5 @@ package redis.clients.jedis.timeseries; -import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -9,7 +8,7 @@ import redis.clients.jedis.Builder; import redis.clients.jedis.BuilderFactory; -import redis.clients.jedis.util.SafeEncoder; +import redis.clients.jedis.util.KeyValue; public final class TimeSeriesBuilderFactory { @@ -49,31 +48,32 @@ public Map build(Object data) { = new Builder>() { @Override public Map build(Object data) { - List dataList = (List) data; + List dataList = (List) data; Map map = new LinkedHashMap<>(dataList.size() / 2, 1f); - for (Iterator iterator = dataList.iterator(); iterator.hasNext();) { - String key = BuilderFactory.STRING.build(iterator.next()); - List valueList = (List) iterator.next(); + for (KeyValue kv : dataList) { + String key = BuilderFactory.STRING.build(kv.getKey()); + List valueList = (List) kv.getValue(); TSMRangeElements elements; switch (valueList.size()) { case 3: List aggrMapObj = (List) valueList.get(1); - assert "aggregators".equalsIgnoreCase(BuilderFactory.STRING.build(aggrMapObj.get(0))); + KeyValue aggKV = (KeyValue) aggrMapObj.get(0); + assert "aggregators".equalsIgnoreCase(BuilderFactory.STRING.build(aggKV.getKey())); elements = new TSMRangeElements(key, BuilderFactory.STRING_MAP.build(valueList.get(0)), - ((List) aggrMapObj.get(1)).stream().map(BuilderFactory.STRING::build) + ((List) aggKV.getValue()).stream().map(BuilderFactory.STRING::build) .map(AggregationType::safeValueOf).collect(Collectors.toList()), TIMESERIES_ELEMENT_LIST.build(valueList.get(2))); break; case 4: - List rdcMapObj = (List) valueList.get(1); - assert "reducers".equalsIgnoreCase(BuilderFactory.STRING.build(rdcMapObj.get(0))); - List srcMapObj = (List) valueList.get(2); - assert "sources".equalsIgnoreCase(BuilderFactory.STRING.build(srcMapObj.get(0))); + List rdcMapObj = (List) valueList.get(1); + assert "reducers".equalsIgnoreCase(BuilderFactory.STRING.build(rdcMapObj.get(0).getKey())); + List srcMapObj = (List) valueList.get(2); + assert "sources".equalsIgnoreCase(BuilderFactory.STRING.build(srcMapObj.get(0).getKey())); elements = new TSMRangeElements(key, BuilderFactory.STRING_MAP.build(valueList.get(0)), - BuilderFactory.STRING_LIST.build(rdcMapObj.get(1)), - BuilderFactory.STRING_LIST.build(srcMapObj.get(1)), + BuilderFactory.STRING_LIST.build(rdcMapObj.get(0).getValue()), + BuilderFactory.STRING_LIST.build(srcMapObj.get(0).getValue()), TIMESERIES_ELEMENT_LIST.build(valueList.get(3))); break; default: @@ -101,11 +101,11 @@ public Map build(Object data) { = new Builder>() { @Override public Map build(Object data) { - List dataList = (List) data; + List dataList = (List) data; Map map = new LinkedHashMap<>(dataList.size()); - for (Iterator iterator = dataList.iterator(); iterator.hasNext();) { - String key = BuilderFactory.STRING.build(iterator.next()); - List valueList = (List) iterator.next(); + for (KeyValue kv : dataList) { + String key = BuilderFactory.STRING.build(kv.getKey()); + List valueList = (List) kv.getValue(); TSMGetElement value = new TSMGetElement(key, BuilderFactory.STRING_MAP.build(valueList.get(0)), TIMESERIES_ELEMENT.build(valueList.get(1))); From 3e10f5242d6cda20418406a7320485bc6b811d44 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Mon, 5 Jun 2023 12:41:53 +0600 Subject: [PATCH 03/10] fix lcs --- src/main/java/redis/clients/jedis/BuilderFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/redis/clients/jedis/BuilderFactory.java b/src/main/java/redis/clients/jedis/BuilderFactory.java index 7ddb8e1da2f..caf2a7e48a0 100644 --- a/src/main/java/redis/clients/jedis/BuilderFactory.java +++ b/src/main/java/redis/clients/jedis/BuilderFactory.java @@ -1661,7 +1661,7 @@ public LCSMatchResult build(Object data) { } } } else { - for (int i = 0; i < objectList.size(); i++) { + for (int i = 0; i < objectList.size(); i += 2) { if ("matches".equalsIgnoreCase(STRING.build(objectList.get(i)))) { addMatchedPosition(matchedPositions, objectList.get(i + 1)); } else if ("len".equalsIgnoreCase(STRING.build(objectList.get(i)))) { From 20a5ffdd40c3a4ef1fb5be66ac9d88f46c14ad39 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Mon, 5 Jun 2023 12:44:22 +0600 Subject: [PATCH 04/10] fix xinfo --- src/main/java/redis/clients/jedis/BuilderFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/redis/clients/jedis/BuilderFactory.java b/src/main/java/redis/clients/jedis/BuilderFactory.java index caf2a7e48a0..623839743cb 100644 --- a/src/main/java/redis/clients/jedis/BuilderFactory.java +++ b/src/main/java/redis/clients/jedis/BuilderFactory.java @@ -1611,7 +1611,7 @@ private static Map createMapFromDecodingFunctions(Iterator Date: Mon, 5 Jun 2023 13:09:30 +0600 Subject: [PATCH 05/10] fix moduleList --- .../redis/clients/jedis/BuilderFactory.java | 51 ++++++++++++------- src/main/java/redis/clients/jedis/Jedis.java | 2 +- src/main/java/redis/clients/jedis/Module.java | 18 ------- .../jedis/commands/jedis/ModuleTest.java | 19 ++++--- 4 files changed, 45 insertions(+), 45 deletions(-) diff --git a/src/main/java/redis/clients/jedis/BuilderFactory.java b/src/main/java/redis/clients/jedis/BuilderFactory.java index 623839743cb..82c8263d561 100644 --- a/src/main/java/redis/clients/jedis/BuilderFactory.java +++ b/src/main/java/redis/clients/jedis/BuilderFactory.java @@ -934,29 +934,44 @@ public Map build(Object data) { return map; } }; +// +// public static final Builder>> ENCODED_OBJECT_MAP_LIST = new Builder>>() { +// @Override +// public List> build(Object data) { +// if (data == null) return null; +// List list = (List) data; +// if (list.isEmpty()) return Collections.emptyList(); +// +// return list.stream().map(ENCODED_OBJECT_MAP::build).collect(Collectors.toList()); +// } +// +// @Override +// public String toString() { +// return "List>"; +// } +// }; - public static final Builder>> ENCODED_OBJECT_MAP_LIST = new Builder>>() { + public static final Builder> MODULE_LIST = new Builder>() { @Override - public List> build(Object data) { - if (data == null) return null; - List list = (List) data; - if (list.isEmpty()) return Collections.emptyList(); + public List build(Object data) { + if (data == null) { + return null; + } - return list.stream().map(ENCODED_OBJECT_MAP::build).collect(Collectors.toList()); - } + List> objectList = (List>) data; - @Override - public String toString() { - return "List>"; - } - }; + List responses = new ArrayList<>(objectList.size()); + if (objectList.isEmpty()) { + return responses; + } - public static final Builder> MODULE_LIST = new Builder>() { - @Override - public List build(Object data) { - List> list = ENCODED_OBJECT_MAP_LIST.build(data); - if (list == null) return null; - return list.stream().map(Module::new).collect(Collectors.toList()); + for (List moduleResp : objectList) { + Module m = new Module(SafeEncoder.encode((byte[]) moduleResp.get(1)), + ((Long) moduleResp.get(3)).intValue()); + responses.add(m); + } + + return responses; } @Override diff --git a/src/main/java/redis/clients/jedis/Jedis.java b/src/main/java/redis/clients/jedis/Jedis.java index cad26491693..5ae990be701 100644 --- a/src/main/java/redis/clients/jedis/Jedis.java +++ b/src/main/java/redis/clients/jedis/Jedis.java @@ -9189,7 +9189,7 @@ public String moduleUnload(final String name) { public List moduleList() { checkIsInMultiOrPipeline(); connection.sendCommand(Command.MODULE, LIST); - return BuilderFactory.MODULE_LIST.build(connection.getObjectMultiBulkReply()); + return BuilderFactory.MODULE_LIST.build(connection.getOne()); } @Override diff --git a/src/main/java/redis/clients/jedis/Module.java b/src/main/java/redis/clients/jedis/Module.java index 833bf5aa6bb..0c3d356c218 100644 --- a/src/main/java/redis/clients/jedis/Module.java +++ b/src/main/java/redis/clients/jedis/Module.java @@ -1,26 +1,15 @@ package redis.clients.jedis; -import java.util.Map; - // TODO: 'resps' package // TODO: remove public class Module { - private final Map info; private final String name; private final int version; - @Deprecated public Module(String name, int version) { this.name = name; this.version = version; - this.info = null; - } - - public Module(Map map) { - this.info = map; - this.name = (String) map.get("name"); - this.version = ((Long) map.get("version")).intValue(); } public String getName() { @@ -31,13 +20,6 @@ public int getVersion() { return version; } - /** - * @return Generic map containing all key-value pairs returned by the server - */ - public Map getInfo() { - return info; - } - @Override public boolean equals(Object o) { if (o == null) return false; diff --git a/src/test/java/redis/clients/jedis/commands/jedis/ModuleTest.java b/src/test/java/redis/clients/jedis/commands/jedis/ModuleTest.java index 2538fc2f5fa..1d4a9d981b5 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/ModuleTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/ModuleTest.java @@ -31,17 +31,20 @@ public byte[] getRaw() { @Test public void testModules() { - assertEquals("OK", jedis.moduleLoad("/tmp/testmodule.so")); + try { + assertEquals("OK", jedis.moduleLoad("/tmp/testmodule.so")); - List modules = jedis.moduleList(); + List modules = jedis.moduleList(); - assertEquals("testmodule", modules.get(0).getName()); - assertEquals("testmodule", modules.get(0).getInfo().get("name")); + assertEquals("testmodule", modules.get(0).getName()); - Object output = jedis.sendCommand(ModuleCommand.SIMPLE); - assertTrue((Long) output > 0); + Object output = jedis.sendCommand(ModuleCommand.SIMPLE); + assertTrue((Long) output > 0); - assertEquals("OK", jedis.moduleUnload("testmodule")); - assertEquals(Collections.emptyList(), jedis.moduleList()); + } finally { + + assertEquals("OK", jedis.moduleUnload("testmodule")); + assertEquals(Collections.emptyList(), jedis.moduleList()); + } } } From 6f69a37a238ecbefe3391a729e9b938edece3fe2 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Mon, 5 Jun 2023 13:12:53 +0600 Subject: [PATCH 06/10] fix timeoutConnection --- src/test/java/redis/clients/jedis/JedisTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/test/java/redis/clients/jedis/JedisTest.java b/src/test/java/redis/clients/jedis/JedisTest.java index f108c687189..df56ea4fb25 100644 --- a/src/test/java/redis/clients/jedis/JedisTest.java +++ b/src/test/java/redis/clients/jedis/JedisTest.java @@ -100,10 +100,12 @@ public void connectOnResp3ProtocolShortcut() { @Test public void timeoutConnection() throws Exception { + final String TIMEOUT_STR = "timeout"; + Jedis jedis = new Jedis("localhost", 6379, 15000); jedis.auth("foobared"); // read current config - final String timeout = jedis.configGet("timeout").get(1); + final String timeout = jedis.configGet(TIMEOUT_STR).get(TIMEOUT_STR); try { jedis.configSet("timeout", "1"); Thread.sleep(5000); @@ -118,7 +120,7 @@ public void timeoutConnection() throws Exception { // reset config jedis = new Jedis("localhost", 6379); jedis.auth("foobared"); - jedis.configSet("timeout", timeout); + jedis.configSet(TIMEOUT_STR, timeout); jedis.close(); } } From d46d1b9ce42629e1c43b6be81a201303559a8b7b Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Mon, 5 Jun 2023 13:16:15 +0600 Subject: [PATCH 07/10] fix aclLog already fixed From 5e368522620ca16110ea5a673ce242adf6ce6558 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Mon, 5 Jun 2023 13:16:24 +0600 Subject: [PATCH 08/10] edit --- src/main/java/redis/clients/jedis/Jedis.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/redis/clients/jedis/Jedis.java b/src/main/java/redis/clients/jedis/Jedis.java index 5ae990be701..e8c15864e36 100644 --- a/src/main/java/redis/clients/jedis/Jedis.java +++ b/src/main/java/redis/clients/jedis/Jedis.java @@ -8416,28 +8416,28 @@ public String aclWhoAmI() { public List aclCat() { checkIsInMultiOrPipeline(); connection.sendCommand(ACL, CAT); - return BuilderFactory.STRING_LIST.build(connection.getObjectMultiBulkReply()); + return BuilderFactory.STRING_LIST.build(connection.getOne()); } @Override public List aclCat(String category) { checkIsInMultiOrPipeline(); connection.sendCommand(ACL, CAT.name(), category); - return BuilderFactory.STRING_LIST.build(connection.getObjectMultiBulkReply()); + return BuilderFactory.STRING_LIST.build(connection.getOne()); } @Override public List aclLog() { checkIsInMultiOrPipeline(); connection.sendCommand(ACL, LOG); - return BuilderFactory.ACCESS_CONTROL_LOG_ENTRY_LIST.build(connection.getObjectMultiBulkReply()); + return BuilderFactory.ACCESS_CONTROL_LOG_ENTRY_LIST.build(connection.getOne()); } @Override public List aclLog(int limit) { checkIsInMultiOrPipeline(); connection.sendCommand(ACL, LOG.getRaw(), toByteArray(limit)); - return BuilderFactory.ACCESS_CONTROL_LOG_ENTRY_LIST.build(connection.getObjectMultiBulkReply()); + return BuilderFactory.ACCESS_CONTROL_LOG_ENTRY_LIST.build(connection.getOne()); } @Override From 4674057adeb4889aa13d24e2fbd9cfa03fae1231 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Mon, 5 Jun 2023 15:26:59 +0600 Subject: [PATCH 09/10] fix moduleList --- src/main/java/redis/clients/jedis/BuilderFactory.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/redis/clients/jedis/BuilderFactory.java b/src/main/java/redis/clients/jedis/BuilderFactory.java index 82c8263d561..c11e82e4f51 100644 --- a/src/main/java/redis/clients/jedis/BuilderFactory.java +++ b/src/main/java/redis/clients/jedis/BuilderFactory.java @@ -966,6 +966,11 @@ public List build(Object data) { } for (List moduleResp : objectList) { + if (moduleResp.get(0) instanceof KeyValue) { + responses.add(new Module(STRING.build(((KeyValue) moduleResp.get(0)).getValue()), + LONG.build(((KeyValue) moduleResp.get(1)).getValue()).intValue())); + continue; + } Module m = new Module(SafeEncoder.encode((byte[]) moduleResp.get(1)), ((Long) moduleResp.get(3)).intValue()); responses.add(m); From ae8a09913f669037dc852044083d2a0b4b425032 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Mon, 5 Jun 2023 16:05:18 +0600 Subject: [PATCH 10/10] fix encodeCompleteResponse --- .../jedis/AllKindOfValuesCommandsTest.java | 9 +- .../commands/jedis/JedisCommandsTestBase.java | 6 +- .../commands/jedis/ScriptingCommandsTest.java | 3 +- .../AllKindOfValuesCommandsTestBase.java | 88 +++++++++++++++---- .../pooled/PooledCommandsTestHelper.java | 4 +- 5 files changed, 80 insertions(+), 30 deletions(-) diff --git a/src/test/java/redis/clients/jedis/commands/jedis/AllKindOfValuesCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/AllKindOfValuesCommandsTest.java index 31e745bdd15..117df767e11 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/AllKindOfValuesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/AllKindOfValuesCommandsTest.java @@ -33,6 +33,7 @@ import redis.clients.jedis.params.SetParams; import redis.clients.jedis.util.AssertUtil; import redis.clients.jedis.util.KeyValue; +import redis.clients.jedis.util.RedisProtocolUtil; public class AllKindOfValuesCommandsTest extends JedisCommandsTestBase { final byte[] bfoo = { 0x01, 0x02, 0x03, 0x04 }; @@ -976,7 +977,7 @@ public void sendBlockingCommandTest() { @Test public void encodeCompleteResponsePing() { - assertEquals("PONG", SafeEncoder.encodeObject(jedis.sendCommand(PING))); + assertEquals("PONG", SafeEncoder.encodeObject(jedis.sendCommand(PING))); } @Test @@ -986,7 +987,7 @@ public void encodeCompleteResponseHgetall() { entries.put("foo2", "bar2"); jedis.hset("hash:test:encode", entries); - if (protocol != RedisProtocol.RESP3) { + if (RedisProtocolUtil.getRedisProtocol() != RedisProtocol.RESP3) { List encodeObj = (List) SafeEncoder.encodeObject(jedis.sendCommand(HGETALL, "hash:test:encode")); assertEquals(4, encodeObj.size()); @@ -1013,7 +1014,7 @@ public void encodeCompleteResponseXinfoStream() { Object obj = jedis.sendCommand(XINFO, "STREAM", "mystream"); - if (protocol != RedisProtocol.RESP3) { + if (RedisProtocolUtil.getRedisProtocol() != RedisProtocol.RESP3) { List encodeObj = (List) SafeEncoder.encodeObject(obj); assertThat(encodeObj.size(), Matchers.greaterThanOrEqualTo(14)); @@ -1041,7 +1042,7 @@ public void encodeCompleteResponseXinfoStream() { entryAsList.add("bar"); assertEquals(entryAsList, ((List) findValueFromMapAsKeyValueList(encodeObj, "first-entry")).get(1)); - assertEquals(entryAsList, ((List) findValueFromMapAsKeyValueList(encodeObj, "last-entry")).get(1)); + assertEquals(entryAsList, ((List) findValueFromMapAsKeyValueList(encodeObj, "last-entry")).get(1)); } } diff --git a/src/test/java/redis/clients/jedis/commands/jedis/JedisCommandsTestBase.java b/src/test/java/redis/clients/jedis/commands/jedis/JedisCommandsTestBase.java index 262eed88cc6..c69302d3c5a 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/JedisCommandsTestBase.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/JedisCommandsTestBase.java @@ -7,13 +7,11 @@ import redis.clients.jedis.HostAndPort; import redis.clients.jedis.Jedis; import redis.clients.jedis.HostAndPorts; -import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.util.RedisProtocolUtil; public abstract class JedisCommandsTestBase { protected static final HostAndPort hnp = HostAndPorts.getRedisServers().get(0); - protected static final RedisProtocol protocol = RedisProtocolUtil.getRedisProtocol(); protected Jedis jedis; @@ -25,7 +23,7 @@ public JedisCommandsTestBase() { public void setUp() throws Exception { // jedis = new Jedis(hnp, DefaultJedisClientConfig.builder().timeoutMillis(500).password("foobared").build()); jedis = new Jedis(hnp, DefaultJedisClientConfig.builder() - .protocol(protocol).timeoutMillis(500).password("foobared").build()); + .protocol(RedisProtocolUtil.getRedisProtocol()).timeoutMillis(500).password("foobared").build()); jedis.flushAll(); } @@ -37,6 +35,6 @@ public void tearDown() throws Exception { protected Jedis createJedis() { // return new Jedis(hnp, DefaultJedisClientConfig.builder().password("foobared").build()); return new Jedis(hnp, DefaultJedisClientConfig.builder() - .protocol(protocol).password("foobared").build()); + .protocol(RedisProtocolUtil.getRedisProtocol()).password("foobared").build()); } } diff --git a/src/test/java/redis/clients/jedis/commands/jedis/ScriptingCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/ScriptingCommandsTest.java index 9d2f01b457c..1e258dbad3b 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/ScriptingCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/ScriptingCommandsTest.java @@ -24,6 +24,7 @@ import redis.clients.jedis.resps.LibraryInfo; import redis.clients.jedis.util.ClientKillerUtil; import redis.clients.jedis.util.KeyValue; +import redis.clients.jedis.util.RedisProtocolUtil; import redis.clients.jedis.util.SafeEncoder; public class ScriptingCommandsTest extends JedisCommandsTestBase { @@ -389,7 +390,7 @@ public void functionList() { assertEquals(functionCode, response.getLibraryCode()); // Binary - if (protocol != RedisProtocol.RESP3) { + if (RedisProtocolUtil.getRedisProtocol() != RedisProtocol.RESP3) { List bresponse = (List) jedis.functionListBinary().get(0); assertArrayEquals(library.getBytes(), (byte[]) bresponse.get(1)); diff --git a/src/test/java/redis/clients/jedis/commands/unified/AllKindOfValuesCommandsTestBase.java b/src/test/java/redis/clients/jedis/commands/unified/AllKindOfValuesCommandsTestBase.java index 176c7b78d7b..07b6fe622ae 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/AllKindOfValuesCommandsTestBase.java +++ b/src/test/java/redis/clients/jedis/commands/unified/AllKindOfValuesCommandsTestBase.java @@ -1,5 +1,6 @@ package redis.clients.jedis.commands.unified; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -28,8 +29,10 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import org.hamcrest.Matchers; import org.junit.Test; +import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.ScanIteration; import redis.clients.jedis.StreamEntryID; import redis.clients.jedis.args.ExpiryOption; @@ -39,6 +42,9 @@ import redis.clients.jedis.exceptions.JedisDataException; import redis.clients.jedis.params.SetParams; import redis.clients.jedis.util.AssertUtil; +import redis.clients.jedis.util.KeyValue; +import redis.clients.jedis.util.RedisProtocolUtil; +import redis.clients.jedis.util.SafeEncoder; public abstract class AllKindOfValuesCommandsTestBase extends UnifiedJedisCommandsTestBase { @@ -788,37 +794,74 @@ public void sendBlockingCommandTest() { } @Test - public void encodeCompleteResponse() { + public void encodeCompleteResponsePing() { + assertEquals("PONG", SafeEncoder.encodeObject(jedis.sendCommand(PING))); + } + + @Test + public void encodeCompleteResponseHgetall() { + HashMap entries = new HashMap<>(); + entries.put("foo", "bar"); + entries.put("foo2", "bar2"); + jedis.hset("hash:test:encode", entries); + + if (RedisProtocolUtil.getRedisProtocol() != RedisProtocol.RESP3) { + List encodeObj = (List) SafeEncoder.encodeObject(jedis.sendCommand(HGETALL, "hash:test:encode")); + + assertEquals(4, encodeObj.size()); + entries.forEach((k, v) -> { + assertThat((Iterable) encodeObj, Matchers.hasItem(k)); + assertEquals(v, findValueFromMapAsList(encodeObj, k)); + }); + } else { + List encodeObj = (List) SafeEncoder.encodeObject(jedis.sendCommand(HGETALL, "hash:test:encode")); + + assertEquals(2, encodeObj.size()); + encodeObj.forEach(kv -> { + assertThat(entries, Matchers.hasEntry(kv.getKey(), kv.getValue())); + }); + } + } + + @Test + public void encodeCompleteResponseXinfoStream() { HashMap entry = new HashMap<>(); entry.put("foo", "bar"); StreamEntryID entryID = jedis.xadd("mystream", StreamEntryID.NEW_ENTRY, entry); jedis.xgroupCreate("mystream", "mygroup", null, false); Object obj = jedis.sendCommand(XINFO, "STREAM", "mystream"); - List encodeObj = (List) encodeObject(obj); - assertTrue(encodeObj.size() >= 14); - assertEquals(0, encodeObj.size() % 2); // must be even + if (RedisProtocolUtil.getRedisProtocol() != RedisProtocol.RESP3) { + List encodeObj = (List) SafeEncoder.encodeObject(obj); + + assertThat(encodeObj.size(), Matchers.greaterThanOrEqualTo(14)); + assertEquals("must have even number of elements", 0, encodeObj.size() % 2); // must be even + + assertEquals(1L, findValueFromMapAsList(encodeObj, "length")); + assertEquals(entryID.toString(), findValueFromMapAsList(encodeObj, "last-generated-id")); - assertEquals(1L, findValueFromMapAsList(encodeObj, "length")); - assertEquals(entryID.toString(), findValueFromMapAsList(encodeObj, "last-generated-id")); + List entryAsList = new ArrayList<>(2); + entryAsList.add("foo"); + entryAsList.add("bar"); - List entryAsList = new ArrayList<>(2); - entryAsList.add("foo"); - entryAsList.add("bar"); + assertEquals(entryAsList, ((List) findValueFromMapAsList(encodeObj, "first-entry")).get(1)); + assertEquals(entryAsList, ((List) findValueFromMapAsList(encodeObj, "last-entry")).get(1)); + } else { + List encodeObj = (List) SafeEncoder.encodeObject(obj); - assertEquals(entryAsList, ((List) findValueFromMapAsList(encodeObj, "first-entry")).get(1)); - assertEquals(entryAsList, ((List) findValueFromMapAsList(encodeObj, "last-entry")).get(1)); + assertThat(encodeObj.size(), Matchers.greaterThanOrEqualTo(7)); - assertEquals("PONG", encodeObject(jedis.sendCommand(PING))); + assertEquals(1L, findValueFromMapAsKeyValueList(encodeObj, "length")); + assertEquals(entryID.toString(), findValueFromMapAsKeyValueList(encodeObj, "last-generated-id")); - entry.put("foo2", "bar2"); - jedis.hset("hash:test:encode", entry); - encodeObj = (List) encodeObject(jedis.sendCommand(HGETALL, "hash:test:encode")); + List entryAsList = new ArrayList<>(2); + entryAsList.add("foo"); + entryAsList.add("bar"); - assertEquals(4, encodeObj.size()); - assertTrue(encodeObj.contains("foo")); - assertTrue(encodeObj.contains("foo2")); + assertEquals(entryAsList, ((List) findValueFromMapAsKeyValueList(encodeObj, "first-entry")).get(1)); + assertEquals(entryAsList, ((List) findValueFromMapAsKeyValueList(encodeObj, "last-entry")).get(1)); + } } private Object findValueFromMapAsList(List list, Object key) { @@ -830,6 +873,15 @@ private Object findValueFromMapAsList(List list, Object key) { return null; } + private Object findValueFromMapAsKeyValueList(List list, Object key) { + for (KeyValue kv : list) { + if (key.equals(kv.getKey())) { + return kv.getValue(); + } + } + return null; + } + @Test public void copy() { assertFalse(jedis.copy("unknown", "foo", false)); diff --git a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledCommandsTestHelper.java b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledCommandsTestHelper.java index 0b8f3b9ca10..42a1e20b79c 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledCommandsTestHelper.java +++ b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledCommandsTestHelper.java @@ -5,13 +5,11 @@ import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPooled; import redis.clients.jedis.HostAndPorts; -import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.util.RedisProtocolUtil; public class PooledCommandsTestHelper { private static final HostAndPort nodeInfo = HostAndPorts.getRedisServers().get(0); - private static final RedisProtocol protocol = RedisProtocolUtil.getRedisProtocol(); private static Jedis node; @@ -23,7 +21,7 @@ static JedisPooled getPooled() throws InterruptedException { //return new JedisPooled(nodeInfo.getHost(), nodeInfo.getPort(), null, "foobared"); return new JedisPooled(nodeInfo, DefaultJedisClientConfig.builder() - .protocol(protocol).password("foobared").build()); + .protocol(RedisProtocolUtil.getRedisProtocol()).password("foobared").build()); } static void clearData() {