From 81ce951b028c937476a28f0737af99d46d3ffd95 Mon Sep 17 00:00:00 2001 From: Alexander Szyrej Date: Mon, 14 Sep 2026 03:41:30 -0300 Subject: [PATCH 1/5] initial support for Jedis --- .../java/controller/redis/RedisValueData.java | 15 +- .../db/redis/RedisHandlerIntegrationTest.java | 6 +- .../redis/RedisHeuristicsCalculatorTest.java | 54 ++++---- client-java/instrumentation/pom.xml | 5 + .../java/instrumentation/RedisCommand.java | 131 ++++++++++++++++-- .../methodreplacement/ReplacementList.java | 1 + .../ConnectionClassReplacement.java | 93 +++++++++++++ .../StatefulConnectionClassReplacement.java | 33 ++++- .../redis/JedisOperationsImpl.java | 29 ++++ .../ConnectionClassReplacementTest.java | 82 +++++++++++ ...tatefulConnectionClassReplacementTest.java | 11 +- .../example/redis/JedisInstrumentedTest.java | 108 +++++++++++++++ .../example/redis/JedisOperations.java | 7 + 13 files changed, 524 insertions(+), 51 deletions(-) create mode 100644 client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/thirdpartyclasses/ConnectionClassReplacement.java create mode 100644 client-java/instrumentation/src/test/java/com/foo/somedifferentpackage/examples/methodreplacement/redis/JedisOperationsImpl.java create mode 100644 client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/thirdpartyclasses/ConnectionClassReplacementTest.java create mode 100644 client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/example/redis/JedisInstrumentedTest.java create mode 100644 client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/example/redis/JedisOperations.java diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisValueData.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisValueData.java index 2d702e093d..4aafaf3dea 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisValueData.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisValueData.java @@ -1,5 +1,7 @@ package org.evomaster.client.java.controller.redis; +import com.fasterxml.jackson.databind.JsonNode; + import java.util.Map; import java.util.Set; @@ -9,10 +11,13 @@ * Fields or members will be set depending on the type of key. * String keys may have a String value in the future, but currently it is not needed to store that information. * Set keys will have the set members. Hash keys will have the fields. + * JSON keys will have the parsed JSON document, needed to navigate JSONPath expressions + * (e.g. JSON.GET/JSON.ARRLEN/JSON.ARRINDEX and similar commands). */ public class RedisValueData { private Map fields; private Set members; + private JsonNode jsonValue; public RedisValueData(Map fields) { this.fields = fields; @@ -22,6 +27,10 @@ public RedisValueData(Set members) { this.members = members; } + public RedisValueData(JsonNode jsonValue) { + this.jsonValue = jsonValue; + } + public Set getMembers() { return members; @@ -30,4 +39,8 @@ public Set getMembers() { public Map getFields() { return fields; } -} + + public JsonNode getJsonValue() { + return jsonValue; + } +} \ No newline at end of file diff --git a/client-java/controller/src/test/java/org/evomaster/client/java/controller/internal/db/redis/RedisHandlerIntegrationTest.java b/client-java/controller/src/test/java/org/evomaster/client/java/controller/internal/db/redis/RedisHandlerIntegrationTest.java index ee451f3409..08d1c32ab4 100644 --- a/client-java/controller/src/test/java/org/evomaster/client/java/controller/internal/db/redis/RedisHandlerIntegrationTest.java +++ b/client-java/controller/src/test/java/org/evomaster/client/java/controller/internal/db/redis/RedisHandlerIntegrationTest.java @@ -51,13 +51,13 @@ void testHeuristicDistanceForStringExists() { RedisCommand similarKeyCmd = new RedisCommand( RedisCommand.RedisCommandType.EXISTS, - new String[]{"key"}, + new String[]{"user:3"}, true, 10 ); RedisCommand differentKeyCmd = new RedisCommand( RedisCommand.RedisCommandType.EXISTS, - new String[]{"key"}, + new String[]{"user:82bd3bff-4567-40f4-a42e-27f87276199f"}, true, 10 ); @@ -94,7 +94,7 @@ void testHeuristicDistanceForStringExists() { void testResetClearsCommands() { RedisCommand cmd = new RedisCommand( RedisCommand.RedisCommandType.EXISTS, - new String[]{"key"}, + new String[]{"user:1"}, true, 5 ); diff --git a/client-java/controller/src/test/java/org/evomaster/client/java/controller/internal/db/redis/RedisHeuristicsCalculatorTest.java b/client-java/controller/src/test/java/org/evomaster/client/java/controller/internal/db/redis/RedisHeuristicsCalculatorTest.java index 3fa3bcb08a..a272478297 100644 --- a/client-java/controller/src/test/java/org/evomaster/client/java/controller/internal/db/redis/RedisHeuristicsCalculatorTest.java +++ b/client-java/controller/src/test/java/org/evomaster/client/java/controller/internal/db/redis/RedisHeuristicsCalculatorTest.java @@ -26,7 +26,7 @@ void setup() { void testKeysPatternExactMatch() { RedisCommand cmd = new RedisCommand( RedisCommand.RedisCommandType.KEYS, - new String[]{"key"}, + new String[]{"user*"}, true, 5 ); @@ -46,7 +46,7 @@ void testKeysPatternExactMatch() { void testKeysPatternNoMatch() { RedisCommand cmd = new RedisCommand( RedisCommand.RedisCommandType.KEYS, - new String[]{"key"}, + new String[]{"thiskeydoesnotexist*"}, true, 5 ); @@ -65,14 +65,14 @@ void testKeysPatternNoMatch() { void testExistsCommandSimilarity() { RedisCommand closeKey = new RedisCommand( RedisCommand.RedisCommandType.EXISTS, - new String[]{"key"}, + new String[]{"user:3"}, true, 5 ); RedisCommand farKey = new RedisCommand( RedisCommand.RedisCommandType.EXISTS, - new String[]{"key"}, + new String[]{"abcxyz"}, true, 5 ); @@ -93,7 +93,7 @@ void testExistsCommandSimilarity() { void testHGetFieldExists() { RedisCommand cmd = new RedisCommand( RedisCommand.RedisCommandType.HGET, - new String[]{"key", "key"}, + new String[]{"profile", "name"}, true, 3 ); @@ -114,7 +114,7 @@ void testHGetFieldExists() { void testHGetFieldNotExists() { RedisCommand cmd = new RedisCommand( RedisCommand.RedisCommandType.HGET, - new String[]{"key", "key"}, + new String[]{"profile", "age"}, true, 3 ); @@ -133,19 +133,19 @@ void testHGetFieldNotExists() { void testHGetFieldDistance() { RedisCommand lowerDistanceCmd = new RedisCommand( RedisCommand.RedisCommandType.HGET, - new String[]{"key", "key"}, + new String[]{"profile", "weight"}, true, 3 ); RedisCommand cmd = new RedisCommand( RedisCommand.RedisCommandType.HGET, - new String[]{"key", "key"}, + new String[]{"profile", "age"}, true, 3 ); RedisCommand greaterDistanceCmd = new RedisCommand( RedisCommand.RedisCommandType.HGET, - new String[]{"key", "key"}, + new String[]{"user", "direction"}, true, 3 ); @@ -168,7 +168,7 @@ void testHGetFieldDistance() { void testSInterSetsIntersectionAndNoIntersection() { RedisCommand cmdIntersect = new RedisCommand( RedisCommand.RedisCommandType.SINTER, - new String[]{"key", "key"}, + new String[]{"setA", "setB"}, true, 1 ); @@ -184,7 +184,7 @@ void testSInterSetsIntersectionAndNoIntersection() { RedisCommand cmdNoIntersect = new RedisCommand( RedisCommand.RedisCommandType.SINTER, - new String[]{"key", "key"}, + new String[]{"setC", "setD"}, true, 1 ); @@ -203,7 +203,7 @@ void testSInterSetsIntersectionAndNoIntersection() { RedisCommand cmdNoIntersectFarDistance = new RedisCommand( RedisCommand.RedisCommandType.SINTER, - new String[]{"key", "key"}, + new String[]{"setE", "setF"}, true, 1 ); @@ -225,7 +225,7 @@ void testSInterSetsIntersectionAndNoIntersection() { void testSInterSeveralSets() { RedisCommand cmdIntersect = new RedisCommand( RedisCommand.RedisCommandType.SINTER, - new String[]{"key", "key", "key", "key"}, + new String[]{"setA", "setB", "setC", "setD"}, true, 1 ); @@ -260,13 +260,13 @@ void testSInterSeveralSets() { void testSMembersSimilarity() { RedisCommand similar = new RedisCommand( RedisCommand.RedisCommandType.SMEMBERS, - new String[]{"key"}, + new String[]{"user:set1"}, true, 2 ); RedisCommand different = new RedisCommand( RedisCommand.RedisCommandType.SMEMBERS, - new String[]{"key"}, + new String[]{"orders"}, true, 2 ); @@ -288,14 +288,14 @@ void testSMembersSimilarity() { void testGetCommandSimilarity() { RedisCommand similar = new RedisCommand( RedisCommand.RedisCommandType.GET, - new String[]{"key"}, + new String[]{"session:1234"}, true, 1 ); RedisCommand different = new RedisCommand( RedisCommand.RedisCommandType.GET, - new String[]{"key"}, + new String[]{"orders"}, true, 1 ); @@ -317,7 +317,7 @@ void testGetCommandSimilarity() { void testComputeDistanceHandlesInternalExceptionOk() { RedisCommand malformedHGet = new RedisCommand( RedisCommand.RedisCommandType.HGET, - new String[]{"key"}, + new String[]{"profile"}, true, 3 ); @@ -338,7 +338,7 @@ void testComputeDistanceHandlesInternalExceptionOk() { void testUnsupportedCommandTypeReturnsMaxDistance() { RedisCommand unsupported = new RedisCommand( RedisCommand.RedisCommandType.SET, - new String[]{"key", "key"}, + new String[]{"foo", "bar"}, true, 1 ); @@ -358,7 +358,7 @@ void testUnsupportedCommandTypeReturnsMaxDistance() { void testHGetAllCommand() { RedisCommand cmd = new RedisCommand( RedisCommand.RedisCommandType.HGETALL, - new String[]{"key"}, + new String[]{"profile"}, true, 1 ); @@ -376,7 +376,7 @@ void testHGetAllCommand() { void testKeyMatchAgainstEmptyDatabase() { RedisCommand cmd = new RedisCommand( RedisCommand.RedisCommandType.GET, - new String[]{"key"}, + new String[]{"anykey"}, true, 1 ); @@ -394,7 +394,7 @@ void testKeyMatchAgainstEmptyDatabase() { void testKeysInvalidPatternIsHandledOk() { RedisCommand cmd = new RedisCommand( RedisCommand.RedisCommandType.KEYS, - new String[]{"key<[abc>"}, + new String[]{"[abc"}, true, 1 ); @@ -416,7 +416,7 @@ void testKeysInvalidPatternIsHandledOk() { void testKeysAgainstEmptyDatabase() { RedisCommand cmd = new RedisCommand( RedisCommand.RedisCommandType.KEYS, - new String[]{"key"}, + new String[]{"user*"}, true, 1 ); @@ -453,7 +453,7 @@ void testSInterWithNoKeysReturnsMaxDistance() { void testSInterAgainstEmptyDatabase() { RedisCommand cmd = new RedisCommand( RedisCommand.RedisCommandType.SINTER, - new String[]{"key", "key"}, + new String[]{"setA", "setB"}, true, 1 ); @@ -471,7 +471,7 @@ void testSInterAgainstEmptyDatabase() { void testSInterWithMissingSetKeyReturnsMaxDistance() { RedisCommand cmd = new RedisCommand( RedisCommand.RedisCommandType.SINTER, - new String[]{"key", "key"}, + new String[]{"setA", "setB"}, true, 1 ); @@ -490,7 +490,7 @@ void testSInterWithMissingSetKeyReturnsMaxDistance() { void testSInterWithAllEmptySetsReturnsMaxDistance() { RedisCommand cmd = new RedisCommand( RedisCommand.RedisCommandType.SINTER, - new String[]{"key", "key"}, + new String[]{"setA", "setB"}, true, 1 ); @@ -510,7 +510,7 @@ void testSInterWithAllEmptySetsReturnsMaxDistance() { void testSInterOneEmptySetAmongNonEmptySetsDoesNotThrow() { RedisCommand cmd = new RedisCommand( RedisCommand.RedisCommandType.SINTER, - new String[]{"key", "key"}, + new String[]{"setA", "setB"}, true, 1 ); diff --git a/client-java/instrumentation/pom.xml b/client-java/instrumentation/pom.xml index b6507eaca5..a227fdb216 100644 --- a/client-java/instrumentation/pom.xml +++ b/client-java/instrumentation/pom.xml @@ -67,6 +67,11 @@ ${springboot.version} test + + redis.clients + jedis + test + org.springframework.boot spring-boot-starter-data-redis diff --git a/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/RedisCommand.java b/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/RedisCommand.java index d836bed6aa..8e5736245d 100644 --- a/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/RedisCommand.java +++ b/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/RedisCommand.java @@ -1,7 +1,6 @@ package org.evomaster.client.java.instrumentation; import java.io.Serializable; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -68,6 +67,127 @@ public enum RedisCommandType { * HSET Documentation */ INCR("incr", "string", false), + /** + * Append one or more json values into the array at path after the last element in it. + * JSON.ARRAPPEND Documentation + */ + JSON_ARRAPPEND("json.arrappend", "json", false), + /** + * Returns the index of the first occurrence of a JSON scalar value in the array at path. + * JSON.ARRINDEX Documentation + */ + JSON_ARRINDEX("json.arrindex", "json", true), + /** + * Inserts the JSON scalar(s) value at the specified index in the array at path. + * JSON.ARRINSERT Documentation + */ + JSON_ARRINSERT("json.arrinsert", "json", false), + /** + * Returns the length of the array at path. + * JSON.ARRLEN Documentation + */ + JSON_ARRLEN("json.arrlen", "json", true), + /** + * Removes and returns the element at the specified index in the array at path. + * JSON.ARRPOP Documentation + */ + JSON_ARRPOP("json.arrpop", "json", false), + /** + * Trims the array at path to contain only the specified inclusive range of indices from start to stop. + * JSON.ARRTRIM Documentation + */ + JSON_ARRTRIM("json.arrtrim", "json", false), + /** + * Clears all values from an array or an object and sets numeric values to 0. + * JSON.CLEAR Documentation + */ + JSON_CLEAR("json.clear", "json", false), + /** + * Debugging container command. + * JSON.DEBUG Documentation + */ + JSON_DEBUG("json.debug", "json", false), + /** + * Deletes a value. + * JSON.DEL Documentation + */ + JSON_DEL("json.del", "json", false), + /** + * Deletes a value. + * JSON.FORGET Documentation + */ + JSON_FORGET("json.forget", "json", false), + /** + * Gets the value at one or more paths in JSON serialized form. + * JSON.GET Documentation + */ + JSON_GET("json.get", "json", true), + /** + * Merges a given JSON value into matching paths. Consequently, JSON values at matching paths + * are updated, deleted, or expanded with new children. + * JSON.MERGE Documentation + */ + JSON_MERGE("json.merge", "json", false), + /** + * Returns the values at a path from one or more keys. + * JSON.MGET Documentation + */ + JSON_MGET("json.mget", "json", true), + /** + * Sets or updates the JSON value of one or more keys. + * JSON.MSET Documentation + */ + JSON_MSET("json.mset", "json", false), + /** + * Increments the numeric value at path by a value. + * JSON.NUMINCRBY Documentation + */ + JSON_NUMINCRBY("json.numincrby", "json", false), + /** + * Multiplies the numeric value at path by a value. + * JSON.NUMMULTBY Documentation + */ + JSON_NUMMULTBY("json.nummultby", "json", false), + /** + * Returns the key names of JSON objects at the paths matching a given path expression. + * JSON.OBJKEYS Documentation + */ + JSON_OBJKEYS("json.objkeys", "json", true), + /** + * Returns the number of keys in JSON objects at the paths matching a given path expression. + * JSON.OBJLEN Documentation + */ + JSON_OBJLEN("json.objlen", "json", true), + /** + * Returns the JSON value at path in Redis Serialization Protocol (RESP). + * JSON.RESP Documentation + */ + JSON_RESP("json.resp", "json", true), + /** + * Sets or updates the JSON value at a path. + * JSON.SET Documentation + */ + JSON_SET("json.set", "json", false), + /** + * Appends a string to JSON strings at the paths matching a given path expression. + * JSON.STRAPPEND Documentation + */ + JSON_STRAPPEND("json.strappend", "json", false), + /** + * Returns the length of JSON strings at the paths matching a given path expression. + * JSON.STRLEN Documentation + */ + JSON_STRLEN("json.strlen", "json", true), + /** + * Toggles a boolean value. + * JSON.TOGGLE Documentation + */ + JSON_TOGGLE("json.toggle", "json", false), + /** + * Returns the type of the JSON value at path. + * JSON.TYPE Documentation + */ + JSON_TYPE("json.type", "json", true), /** * Returns all keys matching pattern. * KEYS Documentation @@ -181,8 +301,7 @@ public boolean shouldCalculateHeuristic() { private final RedisCommandType type; /** - * Keys or values used in query. Keys are used in most queries. Values are used in Set commands. - * Keys are wrapped in {@literal key<...>} while values in {@literal value<...>} + * Already-parsed argument values, in the order the command received them. */ private final String[] args; @@ -215,11 +334,7 @@ public String[] getArgs() { } public List extractArgs(){ - List parameters = new ArrayList<>(); - for(String arg : args){ - parameters.add(arg.substring(arg.indexOf('<')+1, arg.indexOf('>'))); - } - return parameters; + return Arrays.asList(args); } public boolean getSuccessfullyExecuted() { diff --git a/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/ReplacementList.java b/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/ReplacementList.java index 24f2b9d3e2..4be1c6b1fd 100644 --- a/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/ReplacementList.java +++ b/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/ReplacementList.java @@ -31,6 +31,7 @@ public static List getList() { new ByteClassReplacement(), new CharacterClassReplacement(), new CollectionClassReplacement(), + new ConnectionClassReplacement(), new CqlSessionClassReplacement(), new CursorPreparerClassReplacement(), new DateClassReplacement(), diff --git a/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/thirdpartyclasses/ConnectionClassReplacement.java b/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/thirdpartyclasses/ConnectionClassReplacement.java new file mode 100644 index 0000000000..0001aa5262 --- /dev/null +++ b/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/thirdpartyclasses/ConnectionClassReplacement.java @@ -0,0 +1,93 @@ +package org.evomaster.client.java.instrumentation.coverage.methodreplacement.thirdpartyclasses; + +import org.evomaster.client.java.instrumentation.RedisCommand; +import org.evomaster.client.java.instrumentation.coverage.methodreplacement.Replacement; +import org.evomaster.client.java.instrumentation.coverage.methodreplacement.ThirdPartyCast; +import org.evomaster.client.java.instrumentation.coverage.methodreplacement.ThirdPartyMethodReplacementClass; +import org.evomaster.client.java.instrumentation.coverage.methodreplacement.UsageFilter; +import org.evomaster.client.java.instrumentation.shared.ReplacementCategory; +import org.evomaster.client.java.instrumentation.shared.ReplacementType; +import org.evomaster.client.java.instrumentation.staticstate.ExecutionTracer; +import org.evomaster.client.java.utils.SimpleLogger; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * This replacement captures Redis command execution through Jedis. + */ +public class ConnectionClassReplacement extends ThirdPartyMethodReplacementClass { + + private static final ConnectionClassReplacement singleton = new ConnectionClassReplacement(); + + private static final String EXECUTE_COMMAND = "executeCommand"; + + @Override + protected String getNameOfThirdPartyTargetClass() { + return "redis.clients.jedis.Connection"; + } + + @Replacement(replacingStatic = false, type = ReplacementType.TRACKER, id = EXECUTE_COMMAND, + usageFilter = UsageFilter.ANY, category = ReplacementCategory.REDIS) + public static Object executeCommand(Object connection, @ThirdPartyCast(actualType = "redis.clients.jedis.CommandObject") Object commandObject) { + try { + long start = System.currentTimeMillis(); + + Method m = getOriginal(singleton, EXECUTE_COMMAND, connection); + Object result = m.invoke(connection, commandObject); + + long end = System.currentTimeMillis(); + + try { + recordCommand(commandObject, end - start); + } catch (Exception e) { + SimpleLogger.uniqueWarn("Failed to record Redis command captured via Connection.executeCommand: " + e.getMessage()); + } + + return result; + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e.getCause()); + } + } + + private static void recordCommand(Object commandObject, long executionTime) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + Object commandArguments = commandObject.getClass().getMethod("getArguments").invoke(commandObject); + Object protocolCommand = commandArguments.getClass().getMethod("getCommand").invoke(commandArguments); + byte[] rawCommand = (byte[]) protocolCommand.getClass().getMethod("getRaw").invoke(protocolCommand); + String commandName = new String(rawCommand, StandardCharsets.US_ASCII).toUpperCase().replace('.', '_'); + + RedisCommand.RedisCommandType type; + try { + type = RedisCommand.RedisCommandType.valueOf(commandName); + } catch (IllegalArgumentException e) { + type = RedisCommand.RedisCommandType.OTHER; + } + + String[] args = extractArgs(commandArguments); + + RedisCommand cmd = new RedisCommand(type, args, true, executionTime); + ExecutionTracer.addRedisCommand(cmd); + } + + /** + * CommandArguments stores the command keyword itself as the first element + * of the same list it iterates over - already captured as RedisCommandType. + */ + private static String[] extractArgs(Object commandArguments) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + Iterator iterator = (Iterator) commandArguments.getClass().getMethod("iterator").invoke(commandArguments); + List args = new ArrayList<>(); + if (iterator.hasNext()) { + iterator.next(); + } + while (iterator.hasNext()) { + Object rawable = iterator.next(); + byte[] raw = (byte[]) rawable.getClass().getMethod("getRaw").invoke(rawable); + args.add(new String(raw, StandardCharsets.US_ASCII)); + } + return args.toArray(new String[0]); + } +} diff --git a/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/thirdpartyclasses/StatefulConnectionClassReplacement.java b/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/thirdpartyclasses/StatefulConnectionClassReplacement.java index ed28172868..e1aa7c627d 100644 --- a/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/thirdpartyclasses/StatefulConnectionClassReplacement.java +++ b/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/thirdpartyclasses/StatefulConnectionClassReplacement.java @@ -11,6 +11,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.List; /** * This replacement captures Redis dispatch operations containing Redis Commands. @@ -49,10 +50,8 @@ public static Object dispatch(Object redis, @ThirdPartyCast(actualType = "io.let Method argsMethod = command.getClass().getMethod("getArgs"); Object commandArgs = argsMethod.invoke(command); - Method toCmdString = commandArgs.getClass().getMethod("toCommandString"); - String fullCmd = (String) toCmdString.invoke(commandArgs); - String[] args = fullCmd.trim().split("\\s+"); + String[] args = parseArgs(commandArgs); RedisCommand.RedisCommandType cmdType; try { @@ -71,6 +70,34 @@ public static Object dispatch(Object redis, @ThirdPartyCast(actualType = "io.let } } + /** + * Reads CommandArgs's private singularArguments field directly instead of + * calling its public toCommandString(), which joins every argument into a + * single space-separated string - unrecoverable if any argument value + * itself contains a space. Walking the list lets each argument be read on + * its own via toString(), which Lettuce's KeyArgument/ValueArgument render + * as "key<...>"/"value<...>" (unwrapped below); every other argument type + * renders as its plain value. + */ + private static String[] parseArgs(Object commandArgs) { + List singularArguments = (List) getField(commandArgs, "singularArguments"); + String[] args = new String[singularArguments.size()]; + for (int i = 0; i < singularArguments.size(); i++) { + args[i] = unwrapArg(singularArguments.get(i).toString()); + } + return args; + } + + private static String unwrapArg(String token) { + if (token.startsWith("key<") && token.endsWith(">")) { + return token.substring(4, token.length() - 1); + } + if (token.startsWith("value<") && token.endsWith(">")) { + return token.substring(6, token.length() - 1); + } + return token; + } + private static void addRedisCommand(RedisCommand.RedisCommandType type, String[] args, long executionTime) { RedisCommand cmd = new RedisCommand( type, diff --git a/client-java/instrumentation/src/test/java/com/foo/somedifferentpackage/examples/methodreplacement/redis/JedisOperationsImpl.java b/client-java/instrumentation/src/test/java/com/foo/somedifferentpackage/examples/methodreplacement/redis/JedisOperationsImpl.java new file mode 100644 index 0000000000..2bf2e0ab81 --- /dev/null +++ b/client-java/instrumentation/src/test/java/com/foo/somedifferentpackage/examples/methodreplacement/redis/JedisOperationsImpl.java @@ -0,0 +1,29 @@ +package com.foo.somedifferentpackage.examples.methodreplacement.redis; + +import org.evomaster.client.java.instrumentation.example.redis.JedisOperations; +import redis.clients.jedis.HostAndPort; +import redis.clients.jedis.UnifiedJedis; + +public class JedisOperationsImpl implements JedisOperations { + + private final UnifiedJedis jedis; + + public JedisOperationsImpl(String host, int port) { + this.jedis = new UnifiedJedis(new HostAndPort(host, port)); + } + + @Override + public String get(String key) { + return jedis.get(key); + } + + @Override + public Object jsonGet(String key) { + return jedis.jsonGet(key); + } + + @Override + public void jsonSet(String key, Object value) { + jedis.jsonSet(key, value); + } +} diff --git a/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/thirdpartyclasses/ConnectionClassReplacementTest.java b/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/thirdpartyclasses/ConnectionClassReplacementTest.java new file mode 100644 index 0000000000..c14f214e78 --- /dev/null +++ b/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/thirdpartyclasses/ConnectionClassReplacementTest.java @@ -0,0 +1,82 @@ +package org.evomaster.client.java.instrumentation.coverage.methodreplacement.thirdpartyclasses; + +import org.evomaster.client.java.instrumentation.AdditionalInfo; +import org.evomaster.client.java.instrumentation.staticstate.ExecutionTracer; +import org.junit.jupiter.api.*; +import redis.clients.jedis.CommandArguments; +import redis.clients.jedis.CommandObject; +import redis.clients.jedis.Connection; +import redis.clients.jedis.Protocol; +import redis.clients.jedis.args.RawableFactory; +import redis.clients.jedis.commands.ProtocolCommand; +import redis.clients.jedis.util.SafeEncoder; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +public class ConnectionClassReplacementTest { + + private Connection mockConnection; + + private static final String GET = "GET"; + + @BeforeEach + public void setup() { + ExecutionTracer.reset(); + mockConnection = mock(Connection.class); + } + + private enum FakeJsonCommand implements ProtocolCommand { + GET("JSON.GET"); + + private final byte[] raw; + + FakeJsonCommand(String alt) { + raw = SafeEncoder.encode(alt); + } + + @Override + public byte[] getRaw() { + return raw; + } + } + + @Test + public void testExecuteCommandCoreGet() { + String key = "foo"; + CommandArguments args = new CommandArguments(Protocol.Command.GET).key(key); + CommandObject commandObject = new CommandObject<>(args, null); + + ConnectionClassReplacement.executeCommand(mockConnection, commandObject); + + List infoList = ExecutionTracer.exposeAdditionalInfoList(); + assertEquals(1, infoList.size()); + + org.evomaster.client.java.instrumentation.RedisCommand redisCmd = + infoList.get(0).getRedisCommandData().iterator().next(); + + assertEquals(GET, redisCmd.getType().name()); + assertArrayEquals(new String[]{key}, redisCmd.getArgs()); + } + + @Test + public void testExecuteCommandJsonGet() { + String key = "mykey"; + CommandArguments args = new CommandArguments(FakeJsonCommand.GET) + .add(RawableFactory.from(key)); + CommandObject commandObject = new CommandObject<>(args, null); + + ConnectionClassReplacement.executeCommand(mockConnection, commandObject); + + List infoList = ExecutionTracer.exposeAdditionalInfoList(); + assertEquals(1, infoList.size()); + + org.evomaster.client.java.instrumentation.RedisCommand redisCmd = + infoList.get(0).getRedisCommandData().iterator().next(); + + assertEquals("JSON_GET", redisCmd.getType().name()); + assertArrayEquals(new String[]{key}, redisCmd.getArgs()); + } +} diff --git a/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/thirdpartyclasses/StatefulConnectionClassReplacementTest.java b/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/thirdpartyclasses/StatefulConnectionClassReplacementTest.java index 2b57fc52d6..ec9f4bb8ea 100644 --- a/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/thirdpartyclasses/StatefulConnectionClassReplacementTest.java +++ b/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/thirdpartyclasses/StatefulConnectionClassReplacementTest.java @@ -45,7 +45,7 @@ public void testDispatchGet() { org.evomaster.client.java.instrumentation.RedisCommand redisCmd = infoList.get(0).getRedisCommandData().iterator().next(); assertEquals(GET, redisCmd.getType().name()); - assertArrayEquals(new String[]{createKeyArg(key)}, redisCmd.getArgs()); + assertArrayEquals(new String[]{key}, redisCmd.getArgs()); } @Test @@ -66,13 +66,6 @@ public void testDispatchHGet() { org.evomaster.client.java.instrumentation.RedisCommand redisCmd = infoList.get(0).getRedisCommandData().iterator().next(); assertEquals(HGET, redisCmd.getType().name()); - assertArrayEquals(new String[]{ - createKeyArg(key), - createKeyArg(field) - }, redisCmd.getArgs()); - } - - private String createKeyArg(String key) { - return "key<" + key + ">"; + assertArrayEquals(new String[]{key, field}, redisCmd.getArgs()); } } \ No newline at end of file diff --git a/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/example/redis/JedisInstrumentedTest.java b/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/example/redis/JedisInstrumentedTest.java new file mode 100644 index 0000000000..649e8bd970 --- /dev/null +++ b/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/example/redis/JedisInstrumentedTest.java @@ -0,0 +1,108 @@ +package org.evomaster.client.java.instrumentation.example.redis; + +import com.foo.somedifferentpackage.examples.methodreplacement.redis.JedisOperationsImpl; +import org.evomaster.client.java.instrumentation.AdditionalInfo; +import org.evomaster.client.java.instrumentation.InputProperties; +import org.evomaster.client.java.instrumentation.InstrumentingClassLoader; +import org.evomaster.client.java.instrumentation.staticstate.ExecutionTracer; +import org.junit.jupiter.api.*; +import org.testcontainers.containers.GenericContainer; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class JedisInstrumentedTest { + + private static String defaultReplacement; + + private static final int REDIS_PORT = 6379; + + // redis-stack-server, not plain redis, so the JSON module is loaded + // server-side and JSON.GET/JSON.SET don't error out + private static final GenericContainer redisContainer = + new GenericContainer<>("redis/redis-stack-server:latest") + .withExposedPorts(REDIS_PORT); + + private static final String GET = "GET"; + private static final String JSON_GET = "JSON_GET"; + private static final String JSON_SET = "JSON_SET"; + + @BeforeAll + public static void setupAll() { + redisContainer.start(); + + defaultReplacement = System.getProperty(InputProperties.REPLACEMENT_CATEGORIES); + if (defaultReplacement != null) { + System.setProperty(InputProperties.REPLACEMENT_CATEGORIES, defaultReplacement + ",REDIS"); + } else { + System.setProperty(InputProperties.REPLACEMENT_CATEGORIES, "BASE,SQL,EXT_0,NET,MONGO,REDIS"); + } + } + + @AfterAll + public static void teardownAll() { + redisContainer.stop(); + if (defaultReplacement != null) { + System.setProperty(InputProperties.REPLACEMENT_CATEGORIES, defaultReplacement); + } + } + + private JedisOperations getInstance() throws Exception { + InstrumentingClassLoader cl = new InstrumentingClassLoader("com.foo"); + return (JedisOperations) cl.loadClass(JedisOperationsImpl.class.getName()) + .getConstructor(String.class, int.class) + .newInstance(redisContainer.getHost(), redisContainer.getMappedPort(REDIS_PORT)); + } + + @Test + public void testGetInstrumentationWithClassLoader() throws Exception { + ExecutionTracer.reset(); + + JedisOperations jedisInstrumented = getInstance(); + jedisInstrumented.get("foo"); + + List infoList = ExecutionTracer.exposeAdditionalInfoList(); + assertFalse(infoList.isEmpty(), "Expected Redis instrumentation data"); + + boolean foundGet = infoList.stream() + .flatMap(i -> i.getRedisCommandData().stream()) + .anyMatch(cmd -> cmd.getType().name().equals(GET)); + + assertTrue(foundGet, "Expected a GET command to be instrumented via ConnectionClassReplacement"); + } + + @Test + public void testJsonGetInstrumentationWithClassLoader() throws Exception { + ExecutionTracer.reset(); + + JedisOperations jedisInstrumented = getInstance(); + jedisInstrumented.jsonGet("foo"); + + List infoList = ExecutionTracer.exposeAdditionalInfoList(); + assertFalse(infoList.isEmpty(), "Expected Redis instrumentation data"); + + boolean foundJsonGet = infoList.stream() + .flatMap(i -> i.getRedisCommandData().stream()) + .anyMatch(cmd -> cmd.getType().name().equals(JSON_GET)); + + assertTrue(foundJsonGet, "Expected a JSON.GET command to be instrumented via ConnectionClassReplacement"); + } + + @Test + public void testJsonSetInstrumentationWithClassLoader() throws Exception { + ExecutionTracer.reset(); + + JedisOperations jedisInstrumented = getInstance(); + jedisInstrumented.jsonSet("fooSet", "{\"field\":\"bar\"}"); + + List infoList = ExecutionTracer.exposeAdditionalInfoList(); + assertFalse(infoList.isEmpty(), "Expected Redis instrumentation data"); + + boolean foundJsonSet = infoList.stream() + .flatMap(i -> i.getRedisCommandData().stream()) + .anyMatch(cmd -> cmd.getType().name().equals(JSON_SET)); + + assertTrue(foundJsonSet, "Expected a JSON.SET command to be instrumented via ConnectionClassReplacement"); + } +} diff --git a/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/example/redis/JedisOperations.java b/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/example/redis/JedisOperations.java new file mode 100644 index 0000000000..229f4246d7 --- /dev/null +++ b/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/example/redis/JedisOperations.java @@ -0,0 +1,7 @@ +package org.evomaster.client.java.instrumentation.example.redis; + +public interface JedisOperations { + String get(String key); + Object jsonGet(String key); + void jsonSet(String key, Object value); +} From 655932165593a160621cec2987feac0072c87fac Mon Sep 17 00:00:00 2001 From: Alexander Szyrej Date: Mon, 14 Sep 2026 15:58:21 -0300 Subject: [PATCH 2/5] new RedisCommands --- .../java/instrumentation/RedisCommand.java | 1211 ++++++++++++++++- .../ConnectionClassReplacementTest.java | 22 + 2 files changed, 1223 insertions(+), 10 deletions(-) diff --git a/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/RedisCommand.java b/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/RedisCommand.java index 8e5736245d..74e8d5353f 100644 --- a/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/RedisCommand.java +++ b/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/RedisCommand.java @@ -12,12 +12,162 @@ public class RedisCommand implements Serializable { * Redis commands we'd like to capture. Extendable to any other command in Redis that may be of interest. */ public enum RedisCommandType { + /** + * Container command for Access Control List management (CAT, DELUSER, GETUSER, LIST, LOAD, SAVE, SETUSER, WHOAMI subcommands). + * ACL Documentation + */ + ACL("acl", "server", false), + /** + * If key already exists and is a string, this command appends the value at the end of the string. + * APPEND Documentation + */ + APPEND("append", "string", false), + /** + * Used in Redis Cluster to signal that a client is willing to get served by a slot that is in migrating state. + * ASKING Documentation + */ + ASKING("asking", "cluster", false), + /** + * Authenticates the current connection against the server's requirepass, or against a specific user's password with ACL. + * AUTH Documentation + */ + AUTH("auth", "connection", false), + /** + * Instructs Redis to start an Append Only File rewrite process in the background. + * BGREWRITEAOF Documentation + */ + BGREWRITEAOF("bgrewriteaof", "server", false), + /** + * Saves the dataset to disk in the background, forking a child process that persists the data and then exits. + * BGSAVE Documentation + */ + BGSAVE("bgsave", "server", false), + /** + * Count the number of set bits (population counting) in a string. + * BITCOUNT Documentation + */ + BITCOUNT("bitcount", "string", false), + /** + * Treats a Redis string as an array of bits, and is capable of addressing specific integer fields of varying bit widths. + * BITFIELD Documentation + */ + BITFIELD("bitfield", "string", false), + /** + * Read-only variant of BITFIELD, guaranteed to never perform writes even sub-commands seemingly not intended to. + * BITFIELD_RO Documentation + */ + BITFIELD_RO("bitfield_ro", "string", false), + /** + * Perform a bitwise operation between multiple keys and store the result in the destination key. + * BITOP Documentation + */ + BITOP("bitop", "string", false), + /** + * Returns the position of the first bit set to 1 or 0 in a string. + * BITPOS Documentation + */ + BITPOS("bitpos", "string", false), + /** + * Blocking variant of LMOVE, blocks the connection when there are no elements to pop from the source list. + * BLMOVE Documentation + */ + BLMOVE("blmove", "list", false), + /** + * Blocking variant of LMPOP, blocks the connection when there are no elements to pop from any of the given lists. + * BLMPOP Documentation + */ + BLMPOP("blmpop", "list", false), + /** + * Blocking variant of LPOP, blocks the connection when there are no elements to pop from any of the given lists. + * BLPOP Documentation + */ + BLPOP("blpop", "list", false), + /** + * Blocking variant of RPOP, blocks the connection when there are no elements to pop from any of the given lists. + * BRPOP Documentation + */ + BRPOP("brpop", "list", false), + /** + * Blocking variant of RPOPLPUSH, blocks the connection when there are no elements to pop from source. + * BRPOPLPUSH Documentation + */ + BRPOPLPUSH("brpoplpush", "list", false), + /** + * Blocking variant of ZMPOP, blocks the connection when there are no members to pop from any of the given sorted sets. + * BZMPOP Documentation + */ + BZMPOP("bzmpop", "zset", false), + /** + * Blocking variant of ZPOPMAX, blocks the connection when there are no members to pop from any of the given sorted sets. + * BZPOPMAX Documentation + */ + BZPOPMAX("bzpopmax", "zset", false), + /** + * Blocking variant of ZPOPMIN, blocks the connection when there are no members to pop from any of the given sorted sets. + * BZPOPMIN Documentation + */ + BZPOPMIN("bzpopmin", "zset", false), + /** + * Container command for client connection introspection and control (LIST, KILL, SETNAME, GETNAME, PAUSE, NO-EVICT, etc.). + * CLIENT Documentation + */ + CLIENT("client", "server", false), + /** + * Container command for cluster management and introspection (INFO, NODES, SLOTS, SHARDS, MYID subcommands). + * CLUSTER Documentation + */ + CLUSTER("cluster", "cluster", false), + /** + * Returns information about the commands supported by the Redis server (COUNT, DOCS, INFO, LIST, GETKEYS subcommands). + * COMMAND Documentation + */ + COMMAND("command", "server", false), + /** + * Container command for reading and altering server configuration parameters at runtime (GET, SET, REWRITE, RESETSTAT subcommands). + * CONFIG Documentation + */ + CONFIG("config", "server", false), + /** + * Copies the value stored at the source key to the destination key. + * COPY Documentation + */ + COPY("copy", "key", false), + /** + * Return the number of keys in the currently selected database. + * DBSIZE Documentation + */ + DBSIZE("dbsize", "key", false), + /** + * Decrements the number stored at key by one. + * DECR Documentation + */ + DECR("decr", "string", false), + /** + * Decrements the number stored at key by decrement. + * DECRBY Documentation + */ + DECRBY("decrby", "string", false), /** * Removes the specified keys. A key is ignored if it does not exist. * Integer reply: the number of keys that were removed. * DEL Documentation */ DEL("del", "mixed", false), + /** + * Flushes all previously queued commands in a transaction and restores the connection state to normal. + * DISCARD Documentation + */ + DISCARD("discard", "transaction", false), + /** + * Serialize the value stored at key in a Redis-specific format and return it to the user. + * DUMP Documentation + */ + DUMP("dump", "key", false), + /** + * Returns the given string message. + * ECHO Documentation + */ + ECHO("echo", "connection", false), /** * Invoke the execution of a server-side Lua script. * The return value depends on the script that was executed. @@ -30,17 +180,297 @@ public enum RedisCommandType { * EVALSHA Documentation */ EVALSHA("evalsha", "script", false), + /** + * Read-only variant of EVALSHA, guaranteed to never perform writes. + * EVALSHA_RO Documentation + */ + EVALSHA_RO("evalsha_ro", "script", false), + /** + * Read-only variant of EVAL, guaranteed to never perform writes. + * EVAL_RO Documentation + */ + EVAL_RO("eval_ro", "script", false), + /** + * Executes all previously queued commands in a transaction and restores the connection state to normal. + * EXEC Documentation + */ + EXEC("exec", "transaction", false), /** * Returns if key exists. * Integer reply: the number of keys that exist from those specified as arguments. * EXISTS Documentation */ EXISTS("exists", "mixed", true), + /** + * Set a timeout on key, after which the key will automatically be deleted. + * EXPIRE Documentation + */ + EXPIRE("expire", "key", false), + /** + * Has the same effect and semantics as EXPIRE, but instead of specifying the number of seconds, it takes an absolute Unix timestamp. + * EXPIREAT Documentation + */ + EXPIREAT("expireat", "key", false), + /** + * Returns the absolute Unix timestamp at which the given key will expire. + * EXPIRETIME Documentation + */ + EXPIRETIME("expiretime", "key", false), + /** + * Manages a failover to a replica for high availability administrative purposes. + * FAILOVER Documentation + */ + FAILOVER("failover", "server", false), + /** + * Invokes a function previously loaded via FUNCTION LOAD. + * FCALL Documentation + */ + FCALL("fcall", "script", false), + /** + * Read-only variant of FCALL, guaranteed to never perform writes. + * FCALL_RO Documentation + */ + FCALL_RO("fcall_ro", "script", false), + /** + * Delete all the keys of all the existing databases, not just the currently selected one. + * FLUSHALL Documentation + */ + FLUSHALL("flushall", "key", false), + /** + * Delete all the keys of the currently selected DB. + * FLUSHDB Documentation + */ + FLUSHDB("flushdb", "key", false), + /** + * Runs a search query on an index and performs aggregate transformations on the results. + * FT.AGGREGATE Documentation + */ + FT_AGGREGATE("ft.aggregate", "search", false), + /** + * Adds an alias to an index. + * FT.ALIASADD Documentation + */ + FT_ALIASADD("ft.aliasadd", "search", false), + /** + * Removes an alias from an index. + * FT.ALIASDEL Documentation + */ + FT_ALIASDEL("ft.aliasdel", "search", false), + /** + * Adds an alias to an index, removing the alias from any other index it was previously associated with. + * FT.ALIASUPDATE Documentation + */ + FT_ALIASUPDATE("ft.aliasupdate", "search", false), + /** + * Adds a new attribute to an existing index. + * FT.ALTER Documentation + */ + FT_ALTER("ft.alter", "search", false), + /** + * Container command for reading and setting RediSearch runtime configuration options (GET, SET, HELP subcommands). + * FT.CONFIG Documentation + */ + FT_CONFIG("ft.config", "search", false), + /** + * Creates an index with the given specification. + * FT.CREATE Documentation + */ + FT_CREATE("ft.create", "search", false), + /** + * Container command for managing cursors created by FT.AGGREGATE (READ, DEL subcommands). + * FT.CURSOR Documentation + */ + FT_CURSOR("ft.cursor", "search", false), + /** + * Adds terms to a dictionary. + * FT.DICTADD Documentation + */ + FT_DICTADD("ft.dictadd", "search", false), + /** + * Deletes terms from a dictionary. + * FT.DICTDEL Documentation + */ + FT_DICTDEL("ft.dictdel", "search", false), + /** + * Dumps all terms in the given dictionary. + * FT.DICTDUMP Documentation + */ + FT_DICTDUMP("ft.dictdump", "search", false), + /** + * Deletes an index, optionally deleting the documents associated with it. + * FT.DROPINDEX Documentation + */ + FT_DROPINDEX("ft.dropindex", "search", false), + /** + * Returns the execution plan for a complex query. + * FT.EXPLAIN Documentation + */ + FT_EXPLAIN("ft.explain", "search", false), + /** + * Returns the execution plan for a complex query, formatted for the CLI. + * FT.EXPLAINCLI Documentation + */ + FT_EXPLAINCLI("ft.explaincli", "search", false), + /** + * Returns information and statistics about an index. + * FT.INFO Documentation + */ + FT_INFO("ft.info", "search", false), + /** + * Runs a search or aggregate query and returns a profile of how the query was processed. + * FT.PROFILE Documentation + */ + FT_PROFILE("ft.profile", "search", false), + /** + * Searches the index with a textual query, returning either documents or just ids. + * FT.SEARCH Documentation + */ + FT_SEARCH("ft.search", "search", false), + /** + * Performs spelling correction on a query, returning suggestions for misspelled terms. + * FT.SPELLCHECK Documentation + */ + FT_SPELLCHECK("ft.spellcheck", "search", false), + /** + * Adds a suggestion string to an auto-complete suggestion dictionary. + * FT.SUGADD Documentation + */ + FT_SUGADD("ft.sugadd", "search", false), + /** + * Deletes a string from a suggestion index. + * FT.SUGDEL Documentation + */ + FT_SUGDEL("ft.sugdel", "search", false), + /** + * Gets completion suggestions for a prefix from an auto-complete suggestion dictionary. + * FT.SUGGET Documentation + */ + FT_SUGGET("ft.sugget", "search", false), + /** + * Gets the size of an auto-complete suggestion dictionary. + * FT.SUGLEN Documentation + */ + FT_SUGLEN("ft.suglen", "search", false), + /** + * Dumps the contents of a synonym group. + * FT.SYNDUMP Documentation + */ + FT_SYNDUMP("ft.syndump", "search", false), + /** + * Updates a synonym group with additional terms. + * FT.SYNUPDATE Documentation + */ + FT_SYNUPDATE("ft.synupdate", "search", false), + /** + * Returns the distinct values indexed in a Tag field. + * FT.TAGVALS Documentation + */ + FT_TAGVALS("ft.tagvals", "search", false), + /** + * Returns a list of all existing indexes. + * FT._LIST Documentation + */ + FT__LIST("ft._list", "search", false), + /** + * Container command for managing Redis functions, libraries of scripts stored server-side (LOAD, DELETE, LIST, DUMP subcommands). + * FUNCTION Documentation + */ + FUNCTION("function", "script", false), + /** + * Adds the specified geospatial items (longitude, latitude, name) to the specified key. + * GEOADD Documentation + */ + GEOADD("geoadd", "geo", false), + /** + * Returns the distance between two members in the geospatial index represented by the sorted set. + * GEODIST Documentation + */ + GEODIST("geodist", "geo", false), + /** + * Returns valid Geohash strings representing the position of one or more elements in a geospatial data structure. + * GEOHASH Documentation + */ + GEOHASH("geohash", "geo", false), + /** + * Returns the positions (longitude, latitude) of all the specified members in the geospatial index. + * GEOPOS Documentation + */ + GEOPOS("geopos", "geo", false), + /** + * Returns the members of a geospatial index that are within the given distance from the given coordinates. + * GEORADIUS Documentation + */ + GEORADIUS("georadius", "geo", false), + /** + * Returns the members of a geospatial index within a given distance from a member already stored in the index. + * GEORADIUSBYMEMBER Documentation + */ + GEORADIUSBYMEMBER("georadiusbymember", "geo", false), + /** + * Read-only variant of GEORADIUSBYMEMBER, refuses the STORE and STOREDIST options. + * GEORADIUSBYMEMBER_RO Documentation + */ + GEORADIUSBYMEMBER_RO("georadiusbymember_ro", "geo", false), + /** + * Read-only variant of GEORADIUS, refuses the STORE and STOREDIST options. + * GEORADIUS_RO Documentation + */ + GEORADIUS_RO("georadius_ro", "geo", false), + /** + * Searches for members within a geospatial index in a given area, by radius or bounding box. + * GEOSEARCH Documentation + */ + GEOSEARCH("geosearch", "geo", false), + /** + * Similar to GEOSEARCH, but stores the result in the destination key. + * GEOSEARCHSTORE Documentation + */ + GEOSEARCHSTORE("geosearchstore", "geo", false), /** * Get the value of key. * GET Documentation */ GET("get", "string", true), + /** + * Returns the bit value at offset in the string value stored at key. + * GETBIT Documentation + */ + GETBIT("getbit", "string", false), + /** + * Gets the value of key and deletes the key. This command is similar to GET, except for the fact that it also deletes the key on success. + * GETDEL Documentation + */ + GETDEL("getdel", "key", false), + /** + * Gets the value of key and optionally sets its expiration, similarly to SET with the EX/PX/EXAT/PXAT/PERSIST options. + * GETEX Documentation + */ + GETEX("getex", "key", false), + /** + * Returns the substring of the string value stored at key, determined by the offsets start and end. + * GETRANGE Documentation + */ + GETRANGE("getrange", "string", false), + /** + * Atomically sets key to value and returns the old value stored at key. + * GETSET Documentation + */ + GETSET("getset", "string", false), + /** + * Removes the specified fields from the hash stored at key. + * HDEL Documentation + */ + HDEL("hdel", "hash", false), + /** + * Switches the connection's protocol version and returns information about the server and connection. + * HELLO Documentation + */ + HELLO("hello", "connection", false), + /** + * Returns if field is an existing field in the hash stored at key. + * HEXISTS Documentation + */ + HEXISTS("hexists", "hash", false), /** * Returns the value associated with field in the hash stored at key. * HGET Documentation @@ -51,6 +481,68 @@ public enum RedisCommandType { * HGETALL Documentation */ HGETALL("hgetall", "hash", true), + /** + * Increments the number stored at field in the hash stored at key by increment. + * HINCRBY Documentation + */ + HINCRBY("hincrby", "hash", false), + /** + * Increment the specified field of a hash stored at key, and representing a floating point number, by the specified increment. + * HINCRBYFLOAT Documentation + */ + HINCRBYFLOAT("hincrbyfloat", "hash", false), + /** + * Returns all field names in the hash stored at key. + * HKEYS Documentation + */ + HKEYS("hkeys", "hash", false), + /** + * Returns the number of fields contained in the hash stored at key. + * HLEN Documentation + */ + HLEN("hlen", "hash", false), + /** + * Returns the values associated with the specified fields in the hash stored at key. + * HMGET Documentation + */ + HMGET("hmget", "hash", false), + /** + * Deprecated alias for HSET, sets the specified fields to their respective values in the hash stored at key. + * HMSET Documentation + */ + HMSET("hmset", "hash", false), + /** + * Returns one or more random fields from the hash value stored at key. + * HRANDFIELD Documentation + */ + HRANDFIELD("hrandfield", "hash", false), + /** + * Iterates fields of a hash and their associated values, cursor-based, without blocking the server. + * HSCAN Documentation + */ + HSCAN("hscan", "hash", false), + /** + * Sets the specified fields to their respective values in the hash stored at key. + * This command overwrites the values of specified fields that exist in the hash. + * If key doesn't exist, a new key holding a hash is created. + * HSET Documentation + */ + HSET("hset", "hash", false), + /** + * Sets field in the hash stored at key to value, only if field does not yet exist. + * HSETNX Documentation + */ + HSETNX("hsetnx", "hash", false), + /** + * Returns the string length of the value associated with field in the hash stored at key. + * HSTRLEN Documentation + */ + HSTRLEN("hstrlen", "hash", false), + /** + * Returns all values in the hash stored at key. + * HVALS Documentation + */ + HVALS("hvals", "hash", false), /** * Increments the number stored at key by one. * If the key does not exist, it is set to 0 before performing the operation. @@ -59,14 +551,22 @@ public enum RedisCommandType { * This operation is limited to 64-bit signed integers. * INCR Documentation */ - HSET("hset", "hash", false), + INCR("incr", "string", false), /** - * Sets the specified fields to their respective values in the hash stored at key. - * This command overwrites the values of specified fields that exist in the hash. - * If key doesn't exist, a new key holding a hash is created. - * HSET Documentation + * Increments the number stored at key by increment. + * INCRBY Documentation */ - INCR("incr", "string", false), + INCRBY("incrby", "string", false), + /** + * Increment the string representing a floating point number stored at key by the specified increment. + * INCRBYFLOAT Documentation + */ + INCRBYFLOAT("incrbyfloat", "string", false), + /** + * Returns information and statistics about the server in a format that is simple to parse by computers and easy to read by humans. + * INFO Documentation + */ + INFO("info", "server", false), /** * Append one or more json values into the array at path after the last element in it. * JSON.ARRAPPEND Documentation @@ -194,17 +694,276 @@ public enum RedisCommandType { */ KEYS("keys", "none", true), /** - * Set key to hold the string value. If key already holds a value, it is overwritten, regardless of its type. - * Any previous time to live associated with the key is discarded on successful SET operation. - * SET Documentation + * Returns the Unix timestamp of the last successful save to disk. + * LASTSAVE Documentation */ - SET("set", "string", false), + LASTSAVE("lastsave", "server", false), + /** + * Container command for latency monitoring (LATEST, HISTORY, RESET, GRAPH, DOCTOR subcommands). + * LATENCY Documentation + */ + LATENCY("latency", "server", false), + /** + * Implements the longest common subsequence algorithm between the values stored at two keys. + * LCS Documentation + */ + LCS("lcs", "string", false), + /** + * Returns the element at index in the list stored at key. + * LINDEX Documentation + */ + LINDEX("lindex", "list", false), + /** + * Inserts element in the list stored at key either before or after the reference value pivot. + * LINSERT Documentation + */ + LINSERT("linsert", "list", false), + /** + * Returns the length of the list stored at key. + * LLEN Documentation + */ + LLEN("llen", "list", false), + /** + * Atomically returns and removes the first or last element of the list stored at source, and pushes it to the first or last position of the list stored at destination. + * LMOVE Documentation + */ + LMOVE("lmove", "list", false), + /** + * Pops one or more elements from the first non-empty list key from the list of provided key names. + * LMPOP Documentation + */ + LMPOP("lmpop", "list", false), + /** + * Displays a piece of generative computer art together with the Redis version. + * LOLWUT Documentation + */ + LOLWUT("lolwut", "server", false), + /** + * Removes and returns the first elements of the list stored at key. + * LPOP Documentation + */ + LPOP("lpop", "list", false), + /** + * Returns the index of matching elements inside a Redis list. + * LPOS Documentation + */ + LPOS("lpos", "list", false), + /** + * Insert all the specified values at the head of the list stored at key. + * LPUSH Documentation + */ + LPUSH("lpush", "list", false), + /** + * Inserts specified values at the head of the list stored at key, only if key already exists and holds a list. + * LPUSHX Documentation + */ + LPUSHX("lpushx", "list", false), + /** + * Returns the specified elements of the list stored at key, using zero-based start and stop indexes. + * LRANGE Documentation + */ + LRANGE("lrange", "list", false), + /** + * Removes the first count occurrences of elements equal to element from the list stored at key. + * LREM Documentation + */ + LREM("lrem", "list", false), + /** + * Sets the list element at index to value. + * LSET Documentation + */ + LSET("lset", "list", false), + /** + * Trim an existing list so that it will contain only the specified range of elements. + * LTRIM Documentation + */ + LTRIM("ltrim", "list", false), + /** + * Container command for memory introspection (DOCTOR, STATS, USAGE, MALLOC-STATS, PURGE subcommands). + * MEMORY Documentation + */ + MEMORY("memory", "server", false), + /** + * Returns the values of all specified keys, for every key that does not hold a string value a nil value is returned. + * MGET Documentation + */ + MGET("mget", "string", false), + /** + * Atomically transfer a key from a source Redis instance to a destination Redis instance. + * MIGRATE Documentation + */ + MIGRATE("migrate", "key", false), + /** + * Container command for module management (LIST, LOAD, UNLOAD subcommands). + * MODULE Documentation + */ + MODULE("module", "server", false), + /** + * Streams back every command processed by the Redis server, useful for debugging. + * MONITOR Documentation + */ + MONITOR("monitor", "server", false), + /** + * Moves key from the currently selected database to the specified destination database. + * MOVE Documentation + */ + MOVE("move", "key", false), + /** + * Sets the given keys to their respective values, atomically. + * MSET Documentation + */ + MSET("mset", "string", false), + /** + * Sets the given keys to their respective values, only if none of the keys exist. + * MSETNX Documentation + */ + MSETNX("msetnx", "string", false), + /** + * Marks the start of a transaction block. Subsequent commands will be queued for atomic execution using EXEC. + * MULTI Documentation + */ + MULTI("multi", "transaction", false), + /** + * Container command for introspecting the internal representation of Redis objects (ENCODING, FREQ, IDLETIME, REFCOUNT subcommands). + * OBJECT Documentation + */ + OBJECT("object", "key", false), + /** + * Remove the existing timeout on key, turning the key from volatile to persistent. + * PERSIST Documentation + */ + PERSIST("persist", "key", false), + /** + * This command works exactly like EXPIRE but the time to live of the key is specified in milliseconds. + * PEXPIRE Documentation + */ + PEXPIRE("pexpire", "key", false), + /** + * Has the same effect and semantics as EXPIREAT, but the Unix time at which the key will expire is specified in milliseconds. + * PEXPIREAT Documentation + */ + PEXPIREAT("pexpireat", "key", false), + /** + * Returns the absolute Unix timestamp in milliseconds at which the given key will expire. + * PEXPIRETIME Documentation + */ + PEXPIRETIME("pexpiretime", "key", false), + /** + * Adds all the elements to the HyperLogLog data structure stored at the variable name specified as the key. + * PFADD Documentation + */ + PFADD("pfadd", "hyperloglog", false), + /** + * Returns the approximated cardinality of the set observed by the HyperLogLog at key. + * PFCOUNT Documentation + */ + PFCOUNT("pfcount", "hyperloglog", false), + /** + * Merges multiple HyperLogLog values into a unique value that approximates the cardinality of the union of the observed sets. + * PFMERGE Documentation + */ + PFMERGE("pfmerge", "hyperloglog", false), + /** + * Returns PONG if no argument is provided, otherwise returns a copy of the argument as a bulk string. + * PING Documentation + */ + PING("ping", "connection", false), + /** + * Works exactly like SETEX with the sole difference that the expire time is specified in milliseconds instead of seconds. + * PSETEX Documentation + */ + PSETEX("psetex", "string", false), + /** + * Subscribes the client to the given patterns. + * PSUBSCRIBE Documentation + */ + PSUBSCRIBE("psubscribe", "pubsub", false), + /** + * Like TTL, but returns the remaining time to live of a key in milliseconds. + * PTTL Documentation + */ + PTTL("pttl", "key", false), /** * Posts a message to the given channel. * Integer reply: the number of clients that the message was sent to. * PUBLISH Documentation */ PUBLISH("publish", "pubsub", false), + /** + * Container command for introspecting the Pub/Sub subsystem state (CHANNELS, NUMSUB, NUMPAT subcommands). + * PUBSUB Documentation + */ + PUBSUB("pubsub", "pubsub", false), + /** + * Unsubscribes the client from the given patterns, or from all of them if none is given. + * PUNSUBSCRIBE Documentation + */ + PUNSUBSCRIBE("punsubscribe", "pubsub", false), + /** + * Return a random key from the currently selected database. + * RANDOMKEY Documentation + */ + RANDOMKEY("randomkey", "key", false), + /** + * Enables read queries for a connection to a Redis Cluster replica node. + * READONLY Documentation + */ + READONLY("readonly", "cluster", false), + /** + * Disables read queries for a connection to a Redis Cluster replica node, reverting READONLY. + * READWRITE Documentation + */ + READWRITE("readwrite", "cluster", false), + /** + * Renames key to newkey. It returns an error when key does not exist. + * RENAME Documentation + */ + RENAME("rename", "key", false), + /** + * Renames key to newkey if newkey does not yet exist. + * RENAMENX Documentation + */ + RENAMENX("renamenx", "key", false), + /** + * Configures the current instance as a replica of a master instance, or promotes an instance back to being a master. + * REPLICAOF Documentation + */ + REPLICAOF("replicaof", "cluster", false), + /** + * Performs a full reset of the connection's server-side context, discarding MULTI/WATCH state and subscriptions. + * RESET Documentation + */ + RESET("reset", "connection", false), + /** + * Create a key associated with a value that is obtained by deserializing the provided serialized value, obtained via DUMP. + * RESTORE Documentation + */ + RESTORE("restore", "key", false), + /** + * Returns the role of the instance in the context of replication, along with additional replication information. + * ROLE Documentation + */ + ROLE("role", "server", false), + /** + * Removes and returns the last elements of the list stored at key. + * RPOP Documentation + */ + RPOP("rpop", "list", false), + /** + * Atomically returns and removes the last element of the list stored at source, and pushes it to the front of the list stored at destination. + * RPOPLPUSH Documentation + */ + RPOPLPUSH("rpoplpush", "list", false), + /** + * Insert all the specified values at the tail of the list stored at key. + * RPUSH Documentation + */ + RPUSH("rpush", "list", false), + /** + * Inserts specified values at the tail of the list stored at key, only if key already exists and holds a list. + * RPUSHX Documentation + */ + RPUSHX("rpushx", "list", false), /** * Add the specified members to the set stored at key. * Specified members that are already a member of this set are ignored. @@ -213,28 +972,134 @@ public enum RedisCommandType { * SADD Documentation */ SADD("sadd", "set", false), + /** + * Performs a synchronous save of the dataset producing a point in time snapshot of all the data inside the Redis instance. + * SAVE Documentation + */ + SAVE("save", "server", false), + /** + * Iterates the set of keys in the currently selected database, cursor-based, without blocking the server. + * SCAN Documentation + */ + SCAN("scan", "key", false), + /** + * Returns the set cardinality (number of elements) of the set stored at key. + * SCARD Documentation + */ + SCARD("scard", "set", false), + /** + * Container command for script management (LOAD, EXISTS, FLUSH, KILL subcommands). + * SCRIPT Documentation + */ + SCRIPT("script", "script", false), + /** + * Returns the members of the set resulting from the difference between the first set and all the successive sets. + * SDIFF Documentation + */ + SDIFF("sdiff", "set", false), + /** + * Stores the members of the set resulting from the difference between the first set and all the successive sets in destination. + * SDIFFSTORE Documentation + */ + SDIFFSTORE("sdiffstore", "set", false), /** * Select the Redis logical database having the specified zero-based numeric index. * New connections always use the database 0. * SELECT Documentation */ SELECT("select", "none", false), + /** + * Container command for Redis Sentinel administration. + * SENTINEL Documentation + */ + SENTINEL("sentinel", "cluster", false), + /** + * Set key to hold the string value. If key already holds a value, it is overwritten, regardless of its type. + * Any previous time to live associated with the key is discarded on successful SET operation. + * SET Documentation + */ + SET("set", "string", false), + /** + * Sets or clears the bit at offset in the string value stored at key. + * SETBIT Documentation + */ + SETBIT("setbit", "string", false), /** * Set key to hold the string value and set key to timeout after a given number of seconds. * SETEX Documentation */ SETEX("setex", "string", false), + /** + * Set key to hold string value if key does not exist. + * SETNX Documentation + */ + SETNX("setnx", "string", false), + /** + * Overwrites part of the string stored at key, starting at the specified offset. + * SETRANGE Documentation + */ + SETRANGE("setrange", "string", false), + /** + * Synchronously saves the dataset to disk (if configured) and then shuts down the server. + * SHUTDOWN Documentation + */ + SHUTDOWN("shutdown", "server", false), /** * Returns the members of the set resulting from the intersection of all the given sets. * SINTER Documentation */ SINTER("sinter", "set", true), + /** + * Returns the cardinality of the set which would result from the intersection of all the given sets, without actually computing it. + * SINTERCARD Documentation + */ + SINTERCARD("sintercard", "set", false), + /** + * Stores the members of the set resulting from the intersection of all the given sets in destination. + * SINTERSTORE Documentation + */ + SINTERSTORE("sinterstore", "set", false), + /** + * Returns if member is a member of the set stored at key. + * SISMEMBER Documentation + */ + SISMEMBER("sismember", "set", false), + /** + * Deprecated alias for REPLICAOF, configures the current instance as a replica of a master instance, or promotes it to master. + * SLAVEOF Documentation + */ + SLAVEOF("slaveof", "cluster", false), + /** + * Container command for reading and resetting the Redis slow queries log (GET, LEN, RESET subcommands). + * SLOWLOG Documentation + */ + SLOWLOG("slowlog", "server", false), /** * Returns all the members of the set value stored at key. * This has the same effect as running SINTER with one argument key. * SMEMBERS Documentation */ SMEMBERS("smembers", "set", true), + /** + * Returns whether each member is a member of the set stored at key. + * SMISMEMBER Documentation + */ + SMISMEMBER("smismember", "set", false), + /** + * Moves member from the set at source to the set at destination. + * SMOVE Documentation + */ + SMOVE("smove", "set", false), + /** + * Returns or stores the elements contained in the list, set or sorted set at key, sorted or filtered as requested. + * SORT Documentation + */ + SORT("sort", "key", false), + /** + * Read-only variant of the SORT command. Refuses the STORE option and can safely be used in read-only replicas. + * SORT_RO Documentation + */ + SORT_RO("sort_ro", "key", false), /** * Removes and returns one or more random members from the set value store at key. * Nil reply: if the key does not exist. @@ -243,6 +1108,16 @@ public enum RedisCommandType { * SPOP Documentation */ SPOP("spop", "set", false), + /** + * Posts a message to the given shard channel. + * SPUBLISH Documentation + */ + SPUBLISH("spublish", "pubsub", false), + /** + * Returns one or more random members from the set value stored at key, without removing them. + * SRANDMEMBER Documentation + */ + SRANDMEMBER("srandmember", "set", false), /** * Remove the specified members from the set stored at key. * Specified members that are not a member of this set are ignored. @@ -251,6 +1126,21 @@ public enum RedisCommandType { * SREM Documentation */ SREM("srem", "set", false), + /** + * Iterates elements of a set, cursor-based, without blocking the server. + * SSCAN Documentation + */ + SSCAN("sscan", "set", false), + /** + * Subscribes the client to the specified shard channels. + * SSUBSCRIBE Documentation + */ + SSUBSCRIBE("ssubscribe", "pubsub", false), + /** + * Returns the length of the string value stored at key. + * STRLEN Documentation + */ + STRLEN("strlen", "string", false), /** * Subscribes the client to the specified channels. * When successful, this command doesn't return anything. @@ -259,6 +1149,56 @@ public enum RedisCommandType { * SUBSCRIBE Documentation */ SUBSCRIBE("subscribe", "pubsub", false), + /** + * Deprecated alias for GETRANGE, returns the substring of the string value stored at key. + * SUBSTR Documentation + */ + SUBSTR("substr", "string", false), + /** + * Returns the members of the set resulting from the union of all the given sets. + * SUNION Documentation + */ + SUNION("sunion", "set", false), + /** + * Stores the members of the set resulting from the union of all the given sets in destination. + * SUNIONSTORE Documentation + */ + SUNIONSTORE("sunionstore", "set", false), + /** + * Unsubscribes the client from the given shard channels, or from all of them if none is given. + * SUNSUBSCRIBE Documentation + */ + SUNSUBSCRIBE("sunsubscribe", "pubsub", false), + /** + * Swaps two Redis databases, so that immediately all the clients connected to a given database will see the data of the other database. + * SWAPDB Documentation + */ + SWAPDB("swapdb", "key", false), + /** + * Returns the current server time as a two items lists: a Unix timestamp and the amount of microseconds already elapsed in the current second. + * TIME Documentation + */ + TIME("time", "server", false), + /** + * Alters the last access time of the specified keys, returning the number of existing keys specified. + * TOUCH Documentation + */ + TOUCH("touch", "key", false), + /** + * Returns the remaining time to live of a key that has a timeout, in seconds. + * TTL Documentation + */ + TTL("ttl", "key", false), + /** + * Returns the string representation of the type of the value stored at key. + * TYPE Documentation + */ + TYPE("type", "key", false), + /** + * Removes the specified keys, like DEL, but performs the memory reclamation in a different thread, non-blocking. + * UNLINK Documentation + */ + UNLINK("unlink", "key", false), /** * Unsubscribes the client from the given channels, or from all of them if none is given. * When successful, this command doesn't return anything. @@ -267,6 +1207,257 @@ public enum RedisCommandType { * UNSUBSCRIBE Documentation */ UNSUBSCRIBE("unsubscribe", "pubsub", false), + /** + * Flushes all the previously watched keys for a transaction. + * UNWATCH Documentation + */ + UNWATCH("unwatch", "transaction", false), + /** + * Blocks the current client until all the previous write commands are successfully transferred and acknowledged by at least the specified number of replicas. + * WAIT Documentation + */ + WAIT("wait", "server", false), + /** + * Blocks the current client until all previous write commands are successfully written to the append-only file of the local and the specified number of replicas. + * WAITAOF Documentation + */ + WAITAOF("waitaof", "server", false), + /** + * Marks the given keys to be watched for conditional execution of a transaction. + * WATCH Documentation + */ + WATCH("watch", "transaction", false), + /** + * Removes one or multiple messages from the pending entries list of a stream consumer group. + * XACK Documentation + */ + XACK("xack", "stream", false), + /** + * Appends the specified stream entry to the stream at the specified key. + * XADD Documentation + */ + XADD("xadd", "stream", false), + /** + * Transfers ownership of pending stream entries that match the criteria to the specified consumer. + * XAUTOCLAIM Documentation + */ + XAUTOCLAIM("xautoclaim", "stream", false), + /** + * Changes the ownership of a pending message to a different consumer, without acknowledging it. + * XCLAIM Documentation + */ + XCLAIM("xclaim", "stream", false), + /** + * Removes the specified entries from a stream, and returns the number of entries deleted. + * XDEL Documentation + */ + XDEL("xdel", "stream", false), + /** + * Container command for consumer group management (CREATE, SETID, DESTROY, CREATECONSUMER, DELCONSUMER subcommands). + * XGROUP Documentation + */ + XGROUP("xgroup", "stream", false), + /** + * Container command for stream introspection (STREAM, GROUPS, CONSUMERS subcommands). + * XINFO Documentation + */ + XINFO("xinfo", "stream", false), + /** + * Returns the number of entries inside a stream. + * XLEN Documentation + */ + XLEN("xlen", "stream", false), + /** + * Fetches information about pending messages of a given consumer group. + * XPENDING Documentation + */ + XPENDING("xpending", "stream", false), + /** + * Returns the stream entries matching a given range of IDs. + * XRANGE Documentation + */ + XRANGE("xrange", "stream", false), + /** + * Reads data from one or multiple streams, only returning entries with an ID greater than the last received ID. + * XREAD Documentation + */ + XREAD("xread", "stream", false), + /** + * Reads messages from a stream via a consumer group, similarly to XREAD. + * XREADGROUP Documentation + */ + XREADGROUP("xreadgroup", "stream", false), + /** + * Like XRANGE, but returns entries in reverse order, and takes the range in reverse order. + * XREVRANGE Documentation + */ + XREVRANGE("xrevrange", "stream", false), + /** + * Trims the stream by evicting older entries if needed. + * XTRIM Documentation + */ + XTRIM("xtrim", "stream", false), + /** + * Adds all the specified members with the specified scores to the sorted set stored at key. + * ZADD Documentation + */ + ZADD("zadd", "zset", false), + /** + * Returns the sorted set cardinality (number of elements) of the sorted set stored at key. + * ZCARD Documentation + */ + ZCARD("zcard", "zset", false), + /** + * Returns the number of elements in the sorted set at key with a score between min and max. + * ZCOUNT Documentation + */ + ZCOUNT("zcount", "zset", false), + /** + * Computes the difference between the first and all successive sorted sets and returns the result. + * ZDIFF Documentation + */ + ZDIFF("zdiff", "zset", false), + /** + * Computes the difference between the first and all successive sorted sets and stores the result in destination. + * ZDIFFSTORE Documentation + */ + ZDIFFSTORE("zdiffstore", "zset", false), + /** + * Increments the score of member in the sorted set stored at key by increment. + * ZINCRBY Documentation + */ + ZINCRBY("zincrby", "zset", false), + /** + * Computes the intersection of the given sorted sets and returns the result. + * ZINTER Documentation + */ + ZINTER("zinter", "zset", false), + /** + * Returns the cardinality of the intersection of the given sorted sets, without actually computing it. + * ZINTERCARD Documentation + */ + ZINTERCARD("zintercard", "zset", false), + /** + * Computes the intersection of the given sorted sets and stores the result in destination. + * ZINTERSTORE Documentation + */ + ZINTERSTORE("zinterstore", "zset", false), + /** + * Returns the number of elements in the sorted set at key with a value between min and max, when all elements have the same score. + * ZLEXCOUNT Documentation + */ + ZLEXCOUNT("zlexcount", "zset", false), + /** + * Pops one or more elements, with the highest or lowest scores, from the first non-empty sorted set from the list of provided key names. + * ZMPOP Documentation + */ + ZMPOP("zmpop", "zset", false), + /** + * Returns the scores associated with the specified members in the sorted set stored at key. + * ZMSCORE Documentation + */ + ZMSCORE("zmscore", "zset", false), + /** + * Removes and returns up to count members with the highest scores in the sorted set stored at key. + * ZPOPMAX Documentation + */ + ZPOPMAX("zpopmax", "zset", false), + /** + * Removes and returns up to count members with the lowest scores in the sorted set stored at key. + * ZPOPMIN Documentation + */ + ZPOPMIN("zpopmin", "zset", false), + /** + * Returns one or more random members from the sorted set value stored at key. + * ZRANDMEMBER Documentation + */ + ZRANDMEMBER("zrandmember", "zset", false), + /** + * Returns the specified range of elements in the sorted set stored at key. + * ZRANGE Documentation + */ + ZRANGE("zrange", "zset", false), + /** + * Returns all the elements in the sorted set at key with a value between min and max, when all elements have the same score. + * ZRANGEBYLEX Documentation + */ + ZRANGEBYLEX("zrangebylex", "zset", false), + /** + * Returns all the elements in the sorted set at key with a score between min and max. + * ZRANGEBYSCORE Documentation + */ + ZRANGEBYSCORE("zrangebyscore", "zset", false), + /** + * Stores a range of members from the sorted set at source into a new sorted set at destination. + * ZRANGESTORE Documentation + */ + ZRANGESTORE("zrangestore", "zset", false), + /** + * Returns the rank of member in the sorted set stored at key, with the scores ordered from low to high. + * ZRANK Documentation + */ + ZRANK("zrank", "zset", false), + /** + * Removes the specified members from the sorted set stored at key. + * ZREM Documentation + */ + ZREM("zrem", "zset", false), + /** + * Removes all elements in the sorted set between the lexicographical range specified by min and max. + * ZREMRANGEBYLEX Documentation + */ + ZREMRANGEBYLEX("zremrangebylex", "zset", false), + /** + * Removes all elements in the sorted set stored at key with rank between start and stop. + * ZREMRANGEBYRANK Documentation + */ + ZREMRANGEBYRANK("zremrangebyrank", "zset", false), + /** + * Removes all elements in the sorted set stored at key with a score between min and max. + * ZREMRANGEBYSCORE Documentation + */ + ZREMRANGEBYSCORE("zremrangebyscore", "zset", false), + /** + * Returns the specified range of elements in the sorted set stored at key, ordered from the highest to the lowest score. + * ZREVRANGE Documentation + */ + ZREVRANGE("zrevrange", "zset", false), + /** + * Returns all the elements in the sorted set at key with a value between max and min, when all elements have the same score. + * ZREVRANGEBYLEX Documentation + */ + ZREVRANGEBYLEX("zrevrangebylex", "zset", false), + /** + * Returns all the elements in the sorted set at key with a score between max and min, ordered from high to low. + * ZREVRANGEBYSCORE Documentation + */ + ZREVRANGEBYSCORE("zrevrangebyscore", "zset", false), + /** + * Returns the rank of member in the sorted set stored at key, with the scores ordered from high to low. + * ZREVRANK Documentation + */ + ZREVRANK("zrevrank", "zset", false), + /** + * Iterates elements of a sorted set and their scores, cursor-based, without blocking the server. + * ZSCAN Documentation + */ + ZSCAN("zscan", "zset", false), + /** + * Returns the score of member in the sorted set stored at key. + * ZSCORE Documentation + */ + ZSCORE("zscore", "zset", false), + /** + * Computes the union of the given sorted sets and returns the result. + * ZUNION Documentation + */ + ZUNION("zunion", "zset", false), + /** + * Computes the union of the given sorted sets and stores the result in destination. + * ZUNIONSTORE Documentation + */ + ZUNIONSTORE("zunionstore", "zset", false), + /** * Default unregistered command value. */ diff --git a/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/thirdpartyclasses/ConnectionClassReplacementTest.java b/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/thirdpartyclasses/ConnectionClassReplacementTest.java index c14f214e78..436150530f 100644 --- a/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/thirdpartyclasses/ConnectionClassReplacementTest.java +++ b/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/thirdpartyclasses/ConnectionClassReplacementTest.java @@ -9,6 +9,7 @@ import redis.clients.jedis.Protocol; import redis.clients.jedis.args.RawableFactory; import redis.clients.jedis.commands.ProtocolCommand; +import redis.clients.jedis.search.SearchProtocol; import redis.clients.jedis.util.SafeEncoder; import java.util.List; @@ -79,4 +80,25 @@ public void testExecuteCommandJsonGet() { assertEquals("JSON_GET", redisCmd.getType().name()); assertArrayEquals(new String[]{key}, redisCmd.getArgs()); } + + @Test + public void testExecuteCommandFtSearch() { + String indexName = "myIndex"; + String query = "@title:redis"; + CommandArguments args = new CommandArguments(SearchProtocol.SearchCommand.SEARCH) + .add(indexName) + .add(query); + CommandObject commandObject = new CommandObject<>(args, null); + + ConnectionClassReplacement.executeCommand(mockConnection, commandObject); + + List infoList = ExecutionTracer.exposeAdditionalInfoList(); + assertEquals(1, infoList.size()); + + org.evomaster.client.java.instrumentation.RedisCommand redisCmd = + infoList.get(0).getRedisCommandData().iterator().next(); + + assertEquals("FT_SEARCH", redisCmd.getType().name()); + assertArrayEquals(new String[]{indexName, query}, redisCmd.getArgs()); + } } From 4422f76645ad87e150761048580f418bed48f085 Mon Sep 17 00:00:00 2001 From: Alexander Szyrej Date: Tue, 15 Sep 2026 17:55:55 -0300 Subject: [PATCH 3/5] PR changes --- .../evomaster/client/java/instrumentation/RedisCommand.java | 4 ++-- .../examples/methodreplacement/redis/JedisOperationsImpl.java | 4 ++++ .../java/instrumentation/example/redis/JedisOperations.java | 4 ++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/RedisCommand.java b/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/RedisCommand.java index 74e8d5353f..90772326f3 100644 --- a/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/RedisCommand.java +++ b/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/RedisCommand.java @@ -245,7 +245,7 @@ public enum RedisCommandType { * Runs a search query on an index and performs aggregate transformations on the results. * FT.AGGREGATE Documentation */ - FT_AGGREGATE("ft.aggregate", "search", false), + FT_AGGREGATE("ft.aggregate", "search", true), /** * Adds an alias to an index. * FT.ALIASADD Documentation @@ -325,7 +325,7 @@ public enum RedisCommandType { * Searches the index with a textual query, returning either documents or just ids. * FT.SEARCH Documentation */ - FT_SEARCH("ft.search", "search", false), + FT_SEARCH("ft.search", "search", true), /** * Performs spelling correction on a query, returning suggestions for misspelled terms. * FT.SPELLCHECK Documentation diff --git a/client-java/instrumentation/src/test/java/com/foo/somedifferentpackage/examples/methodreplacement/redis/JedisOperationsImpl.java b/client-java/instrumentation/src/test/java/com/foo/somedifferentpackage/examples/methodreplacement/redis/JedisOperationsImpl.java index 2bf2e0ab81..eb56763a12 100644 --- a/client-java/instrumentation/src/test/java/com/foo/somedifferentpackage/examples/methodreplacement/redis/JedisOperationsImpl.java +++ b/client-java/instrumentation/src/test/java/com/foo/somedifferentpackage/examples/methodreplacement/redis/JedisOperationsImpl.java @@ -4,6 +4,10 @@ import redis.clients.jedis.HostAndPort; import redis.clients.jedis.UnifiedJedis; +/** + * {@link JedisOperations} implementation backed by a real {@link UnifiedJedis} connection, + * used as the instrumentation target in JedisInstrumentedTest. + */ public class JedisOperationsImpl implements JedisOperations { private final UnifiedJedis jedis; diff --git a/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/example/redis/JedisOperations.java b/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/example/redis/JedisOperations.java index 229f4246d7..c49850d11f 100644 --- a/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/example/redis/JedisOperations.java +++ b/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/example/redis/JedisOperations.java @@ -1,5 +1,9 @@ package org.evomaster.client.java.instrumentation.example.redis; +/** + * Minimal Jedis-backed Redis client used to verify method-replacement instrumentation + * on {@link org.evomaster.client.java.instrumentation.coverage.methodreplacement.thirdpartyclasses.ConnectionClassReplacement}. + */ public interface JedisOperations { String get(String key); Object jsonGet(String key); From a4e397cb86de0aed24b4e922312613d929e7f16d Mon Sep 17 00:00:00 2001 From: Alexander Szyrej Date: Tue, 15 Sep 2026 23:20:24 -0300 Subject: [PATCH 4/5] Redis command now includes only FT commands for new case studies --- .../java/instrumentation/RedisCommand.java | 1400 +---------------- 1 file changed, 49 insertions(+), 1351 deletions(-) diff --git a/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/RedisCommand.java b/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/RedisCommand.java index 90772326f3..9e1880046c 100644 --- a/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/RedisCommand.java +++ b/client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/RedisCommand.java @@ -12,958 +12,88 @@ public class RedisCommand implements Serializable { * Redis commands we'd like to capture. Extendable to any other command in Redis that may be of interest. */ public enum RedisCommandType { - /** - * Container command for Access Control List management (CAT, DELUSER, GETUSER, LIST, LOAD, SAVE, SETUSER, WHOAMI subcommands). - * ACL Documentation - */ - ACL("acl", "server", false), - /** - * If key already exists and is a string, this command appends the value at the end of the string. - * APPEND Documentation - */ - APPEND("append", "string", false), - /** - * Used in Redis Cluster to signal that a client is willing to get served by a slot that is in migrating state. - * ASKING Documentation - */ - ASKING("asking", "cluster", false), - /** - * Authenticates the current connection against the server's requirepass, or against a specific user's password with ACL. - * AUTH Documentation - */ - AUTH("auth", "connection", false), - /** - * Instructs Redis to start an Append Only File rewrite process in the background. - * BGREWRITEAOF Documentation - */ - BGREWRITEAOF("bgrewriteaof", "server", false), - /** - * Saves the dataset to disk in the background, forking a child process that persists the data and then exits. - * BGSAVE Documentation - */ - BGSAVE("bgsave", "server", false), - /** - * Count the number of set bits (population counting) in a string. - * BITCOUNT Documentation - */ - BITCOUNT("bitcount", "string", false), - /** - * Treats a Redis string as an array of bits, and is capable of addressing specific integer fields of varying bit widths. - * BITFIELD Documentation - */ - BITFIELD("bitfield", "string", false), - /** - * Read-only variant of BITFIELD, guaranteed to never perform writes even sub-commands seemingly not intended to. - * BITFIELD_RO Documentation - */ - BITFIELD_RO("bitfield_ro", "string", false), - /** - * Perform a bitwise operation between multiple keys and store the result in the destination key. - * BITOP Documentation - */ - BITOP("bitop", "string", false), - /** - * Returns the position of the first bit set to 1 or 0 in a string. - * BITPOS Documentation - */ - BITPOS("bitpos", "string", false), - /** - * Blocking variant of LMOVE, blocks the connection when there are no elements to pop from the source list. - * BLMOVE Documentation - */ - BLMOVE("blmove", "list", false), - /** - * Blocking variant of LMPOP, blocks the connection when there are no elements to pop from any of the given lists. - * BLMPOP Documentation - */ - BLMPOP("blmpop", "list", false), - /** - * Blocking variant of LPOP, blocks the connection when there are no elements to pop from any of the given lists. - * BLPOP Documentation - */ - BLPOP("blpop", "list", false), - /** - * Blocking variant of RPOP, blocks the connection when there are no elements to pop from any of the given lists. - * BRPOP Documentation - */ - BRPOP("brpop", "list", false), - /** - * Blocking variant of RPOPLPUSH, blocks the connection when there are no elements to pop from source. - * BRPOPLPUSH Documentation - */ - BRPOPLPUSH("brpoplpush", "list", false), - /** - * Blocking variant of ZMPOP, blocks the connection when there are no members to pop from any of the given sorted sets. - * BZMPOP Documentation - */ - BZMPOP("bzmpop", "zset", false), - /** - * Blocking variant of ZPOPMAX, blocks the connection when there are no members to pop from any of the given sorted sets. - * BZPOPMAX Documentation - */ - BZPOPMAX("bzpopmax", "zset", false), - /** - * Blocking variant of ZPOPMIN, blocks the connection when there are no members to pop from any of the given sorted sets. - * BZPOPMIN Documentation - */ - BZPOPMIN("bzpopmin", "zset", false), - /** - * Container command for client connection introspection and control (LIST, KILL, SETNAME, GETNAME, PAUSE, NO-EVICT, etc.). - * CLIENT Documentation - */ - CLIENT("client", "server", false), - /** - * Container command for cluster management and introspection (INFO, NODES, SLOTS, SHARDS, MYID subcommands). - * CLUSTER Documentation - */ - CLUSTER("cluster", "cluster", false), - /** - * Returns information about the commands supported by the Redis server (COUNT, DOCS, INFO, LIST, GETKEYS subcommands). - * COMMAND Documentation - */ - COMMAND("command", "server", false), - /** - * Container command for reading and altering server configuration parameters at runtime (GET, SET, REWRITE, RESETSTAT subcommands). - * CONFIG Documentation - */ - CONFIG("config", "server", false), - /** - * Copies the value stored at the source key to the destination key. - * COPY Documentation - */ - COPY("copy", "key", false), - /** - * Return the number of keys in the currently selected database. - * DBSIZE Documentation - */ - DBSIZE("dbsize", "key", false), - /** - * Decrements the number stored at key by one. - * DECR Documentation - */ - DECR("decr", "string", false), - /** - * Decrements the number stored at key by decrement. - * DECRBY Documentation - */ - DECRBY("decrby", "string", false), /** * Removes the specified keys. A key is ignored if it does not exist. - * Integer reply: the number of keys that were removed. - * DEL Documentation - */ - DEL("del", "mixed", false), - /** - * Flushes all previously queued commands in a transaction and restores the connection state to normal. - * DISCARD Documentation - */ - DISCARD("discard", "transaction", false), - /** - * Serialize the value stored at key in a Redis-specific format and return it to the user. - * DUMP Documentation - */ - DUMP("dump", "key", false), - /** - * Returns the given string message. - * ECHO Documentation - */ - ECHO("echo", "connection", false), - /** - * Invoke the execution of a server-side Lua script. - * The return value depends on the script that was executed. - * EVAL Documentation - */ - EVAL("eval", "script", false), - /** - * Evaluate a script from the server's cache by its SHA1 digest. - * The return value depends on the script that was executed. - * EVALSHA Documentation - */ - EVALSHA("evalsha", "script", false), - /** - * Read-only variant of EVALSHA, guaranteed to never perform writes. - * EVALSHA_RO Documentation - */ - EVALSHA_RO("evalsha_ro", "script", false), - /** - * Read-only variant of EVAL, guaranteed to never perform writes. - * EVAL_RO Documentation - */ - EVAL_RO("eval_ro", "script", false), - /** - * Executes all previously queued commands in a transaction and restores the connection state to normal. - * EXEC Documentation - */ - EXEC("exec", "transaction", false), - /** - * Returns if key exists. - * Integer reply: the number of keys that exist from those specified as arguments. - * EXISTS Documentation - */ - EXISTS("exists", "mixed", true), - /** - * Set a timeout on key, after which the key will automatically be deleted. - * EXPIRE Documentation - */ - EXPIRE("expire", "key", false), - /** - * Has the same effect and semantics as EXPIRE, but instead of specifying the number of seconds, it takes an absolute Unix timestamp. - * EXPIREAT Documentation - */ - EXPIREAT("expireat", "key", false), - /** - * Returns the absolute Unix timestamp at which the given key will expire. - * EXPIRETIME Documentation - */ - EXPIRETIME("expiretime", "key", false), - /** - * Manages a failover to a replica for high availability administrative purposes. - * FAILOVER Documentation - */ - FAILOVER("failover", "server", false), - /** - * Invokes a function previously loaded via FUNCTION LOAD. - * FCALL Documentation - */ - FCALL("fcall", "script", false), - /** - * Read-only variant of FCALL, guaranteed to never perform writes. - * FCALL_RO Documentation - */ - FCALL_RO("fcall_ro", "script", false), - /** - * Delete all the keys of all the existing databases, not just the currently selected one. - * FLUSHALL Documentation - */ - FLUSHALL("flushall", "key", false), - /** - * Delete all the keys of the currently selected DB. - * FLUSHDB Documentation - */ - FLUSHDB("flushdb", "key", false), - /** - * Runs a search query on an index and performs aggregate transformations on the results. - * FT.AGGREGATE Documentation - */ - FT_AGGREGATE("ft.aggregate", "search", true), - /** - * Adds an alias to an index. - * FT.ALIASADD Documentation - */ - FT_ALIASADD("ft.aliasadd", "search", false), - /** - * Removes an alias from an index. - * FT.ALIASDEL Documentation - */ - FT_ALIASDEL("ft.aliasdel", "search", false), - /** - * Adds an alias to an index, removing the alias from any other index it was previously associated with. - * FT.ALIASUPDATE Documentation - */ - FT_ALIASUPDATE("ft.aliasupdate", "search", false), - /** - * Adds a new attribute to an existing index. - * FT.ALTER Documentation - */ - FT_ALTER("ft.alter", "search", false), - /** - * Container command for reading and setting RediSearch runtime configuration options (GET, SET, HELP subcommands). - * FT.CONFIG Documentation - */ - FT_CONFIG("ft.config", "search", false), - /** - * Creates an index with the given specification. - * FT.CREATE Documentation - */ - FT_CREATE("ft.create", "search", false), - /** - * Container command for managing cursors created by FT.AGGREGATE (READ, DEL subcommands). - * FT.CURSOR Documentation - */ - FT_CURSOR("ft.cursor", "search", false), - /** - * Adds terms to a dictionary. - * FT.DICTADD Documentation - */ - FT_DICTADD("ft.dictadd", "search", false), - /** - * Deletes terms from a dictionary. - * FT.DICTDEL Documentation - */ - FT_DICTDEL("ft.dictdel", "search", false), - /** - * Dumps all terms in the given dictionary. - * FT.DICTDUMP Documentation - */ - FT_DICTDUMP("ft.dictdump", "search", false), - /** - * Deletes an index, optionally deleting the documents associated with it. - * FT.DROPINDEX Documentation - */ - FT_DROPINDEX("ft.dropindex", "search", false), - /** - * Returns the execution plan for a complex query. - * FT.EXPLAIN Documentation - */ - FT_EXPLAIN("ft.explain", "search", false), - /** - * Returns the execution plan for a complex query, formatted for the CLI. - * FT.EXPLAINCLI Documentation - */ - FT_EXPLAINCLI("ft.explaincli", "search", false), - /** - * Returns information and statistics about an index. - * FT.INFO Documentation - */ - FT_INFO("ft.info", "search", false), - /** - * Runs a search or aggregate query and returns a profile of how the query was processed. - * FT.PROFILE Documentation - */ - FT_PROFILE("ft.profile", "search", false), - /** - * Searches the index with a textual query, returning either documents or just ids. - * FT.SEARCH Documentation - */ - FT_SEARCH("ft.search", "search", true), - /** - * Performs spelling correction on a query, returning suggestions for misspelled terms. - * FT.SPELLCHECK Documentation - */ - FT_SPELLCHECK("ft.spellcheck", "search", false), - /** - * Adds a suggestion string to an auto-complete suggestion dictionary. - * FT.SUGADD Documentation - */ - FT_SUGADD("ft.sugadd", "search", false), - /** - * Deletes a string from a suggestion index. - * FT.SUGDEL Documentation - */ - FT_SUGDEL("ft.sugdel", "search", false), - /** - * Gets completion suggestions for a prefix from an auto-complete suggestion dictionary. - * FT.SUGGET Documentation - */ - FT_SUGGET("ft.sugget", "search", false), - /** - * Gets the size of an auto-complete suggestion dictionary. - * FT.SUGLEN Documentation - */ - FT_SUGLEN("ft.suglen", "search", false), - /** - * Dumps the contents of a synonym group. - * FT.SYNDUMP Documentation - */ - FT_SYNDUMP("ft.syndump", "search", false), - /** - * Updates a synonym group with additional terms. - * FT.SYNUPDATE Documentation - */ - FT_SYNUPDATE("ft.synupdate", "search", false), - /** - * Returns the distinct values indexed in a Tag field. - * FT.TAGVALS Documentation - */ - FT_TAGVALS("ft.tagvals", "search", false), - /** - * Returns a list of all existing indexes. - * FT._LIST Documentation - */ - FT__LIST("ft._list", "search", false), - /** - * Container command for managing Redis functions, libraries of scripts stored server-side (LOAD, DELETE, LIST, DUMP subcommands). - * FUNCTION Documentation - */ - FUNCTION("function", "script", false), - /** - * Adds the specified geospatial items (longitude, latitude, name) to the specified key. - * GEOADD Documentation - */ - GEOADD("geoadd", "geo", false), - /** - * Returns the distance between two members in the geospatial index represented by the sorted set. - * GEODIST Documentation - */ - GEODIST("geodist", "geo", false), - /** - * Returns valid Geohash strings representing the position of one or more elements in a geospatial data structure. - * GEOHASH Documentation - */ - GEOHASH("geohash", "geo", false), - /** - * Returns the positions (longitude, latitude) of all the specified members in the geospatial index. - * GEOPOS Documentation - */ - GEOPOS("geopos", "geo", false), - /** - * Returns the members of a geospatial index that are within the given distance from the given coordinates. - * GEORADIUS Documentation - */ - GEORADIUS("georadius", "geo", false), - /** - * Returns the members of a geospatial index within a given distance from a member already stored in the index. - * GEORADIUSBYMEMBER Documentation - */ - GEORADIUSBYMEMBER("georadiusbymember", "geo", false), - /** - * Read-only variant of GEORADIUSBYMEMBER, refuses the STORE and STOREDIST options. - * GEORADIUSBYMEMBER_RO Documentation - */ - GEORADIUSBYMEMBER_RO("georadiusbymember_ro", "geo", false), - /** - * Read-only variant of GEORADIUS, refuses the STORE and STOREDIST options. - * GEORADIUS_RO Documentation - */ - GEORADIUS_RO("georadius_ro", "geo", false), - /** - * Searches for members within a geospatial index in a given area, by radius or bounding box. - * GEOSEARCH Documentation - */ - GEOSEARCH("geosearch", "geo", false), - /** - * Similar to GEOSEARCH, but stores the result in the destination key. - * GEOSEARCHSTORE Documentation - */ - GEOSEARCHSTORE("geosearchstore", "geo", false), - /** - * Get the value of key. - * GET Documentation - */ - GET("get", "string", true), - /** - * Returns the bit value at offset in the string value stored at key. - * GETBIT Documentation - */ - GETBIT("getbit", "string", false), - /** - * Gets the value of key and deletes the key. This command is similar to GET, except for the fact that it also deletes the key on success. - * GETDEL Documentation - */ - GETDEL("getdel", "key", false), - /** - * Gets the value of key and optionally sets its expiration, similarly to SET with the EX/PX/EXAT/PXAT/PERSIST options. - * GETEX Documentation - */ - GETEX("getex", "key", false), - /** - * Returns the substring of the string value stored at key, determined by the offsets start and end. - * GETRANGE Documentation - */ - GETRANGE("getrange", "string", false), - /** - * Atomically sets key to value and returns the old value stored at key. - * GETSET Documentation - */ - GETSET("getset", "string", false), - /** - * Removes the specified fields from the hash stored at key. - * HDEL Documentation - */ - HDEL("hdel", "hash", false), - /** - * Switches the connection's protocol version and returns information about the server and connection. - * HELLO Documentation - */ - HELLO("hello", "connection", false), - /** - * Returns if field is an existing field in the hash stored at key. - * HEXISTS Documentation - */ - HEXISTS("hexists", "hash", false), - /** - * Returns the value associated with field in the hash stored at key. - * HGET Documentation - */ - HGET("hget", "hash", true), - /** - * Returns all fields and values of the hash stored at key. - * HGETALL Documentation - */ - HGETALL("hgetall", "hash", true), - /** - * Increments the number stored at field in the hash stored at key by increment. - * HINCRBY Documentation - */ - HINCRBY("hincrby", "hash", false), - /** - * Increment the specified field of a hash stored at key, and representing a floating point number, by the specified increment. - * HINCRBYFLOAT Documentation - */ - HINCRBYFLOAT("hincrbyfloat", "hash", false), - /** - * Returns all field names in the hash stored at key. - * HKEYS Documentation - */ - HKEYS("hkeys", "hash", false), - /** - * Returns the number of fields contained in the hash stored at key. - * HLEN Documentation - */ - HLEN("hlen", "hash", false), - /** - * Returns the values associated with the specified fields in the hash stored at key. - * HMGET Documentation - */ - HMGET("hmget", "hash", false), - /** - * Deprecated alias for HSET, sets the specified fields to their respective values in the hash stored at key. - * HMSET Documentation - */ - HMSET("hmset", "hash", false), - /** - * Returns one or more random fields from the hash value stored at key. - * HRANDFIELD Documentation - */ - HRANDFIELD("hrandfield", "hash", false), - /** - * Iterates fields of a hash and their associated values, cursor-based, without blocking the server. - * HSCAN Documentation - */ - HSCAN("hscan", "hash", false), - /** - * Sets the specified fields to their respective values in the hash stored at key. - * This command overwrites the values of specified fields that exist in the hash. - * If key doesn't exist, a new key holding a hash is created. - * HSET Documentation - */ - HSET("hset", "hash", false), - /** - * Sets field in the hash stored at key to value, only if field does not yet exist. - * HSETNX Documentation - */ - HSETNX("hsetnx", "hash", false), - /** - * Returns the string length of the value associated with field in the hash stored at key. - * HSTRLEN Documentation - */ - HSTRLEN("hstrlen", "hash", false), - /** - * Returns all values in the hash stored at key. - * HVALS Documentation - */ - HVALS("hvals", "hash", false), - /** - * Increments the number stored at key by one. - * If the key does not exist, it is set to 0 before performing the operation. - * An error is returned if the key contains a value of the wrong type - * or contains a string that can not be represented as integer. - * This operation is limited to 64-bit signed integers. - * INCR Documentation - */ - INCR("incr", "string", false), - /** - * Increments the number stored at key by increment. - * INCRBY Documentation - */ - INCRBY("incrby", "string", false), - /** - * Increment the string representing a floating point number stored at key by the specified increment. - * INCRBYFLOAT Documentation - */ - INCRBYFLOAT("incrbyfloat", "string", false), - /** - * Returns information and statistics about the server in a format that is simple to parse by computers and easy to read by humans. - * INFO Documentation - */ - INFO("info", "server", false), - /** - * Append one or more json values into the array at path after the last element in it. - * JSON.ARRAPPEND Documentation - */ - JSON_ARRAPPEND("json.arrappend", "json", false), - /** - * Returns the index of the first occurrence of a JSON scalar value in the array at path. - * JSON.ARRINDEX Documentation - */ - JSON_ARRINDEX("json.arrindex", "json", true), - /** - * Inserts the JSON scalar(s) value at the specified index in the array at path. - * JSON.ARRINSERT Documentation - */ - JSON_ARRINSERT("json.arrinsert", "json", false), - /** - * Returns the length of the array at path. - * JSON.ARRLEN Documentation - */ - JSON_ARRLEN("json.arrlen", "json", true), - /** - * Removes and returns the element at the specified index in the array at path. - * JSON.ARRPOP Documentation - */ - JSON_ARRPOP("json.arrpop", "json", false), - /** - * Trims the array at path to contain only the specified inclusive range of indices from start to stop. - * JSON.ARRTRIM Documentation - */ - JSON_ARRTRIM("json.arrtrim", "json", false), - /** - * Clears all values from an array or an object and sets numeric values to 0. - * JSON.CLEAR Documentation - */ - JSON_CLEAR("json.clear", "json", false), - /** - * Debugging container command. - * JSON.DEBUG Documentation - */ - JSON_DEBUG("json.debug", "json", false), - /** - * Deletes a value. - * JSON.DEL Documentation - */ - JSON_DEL("json.del", "json", false), - /** - * Deletes a value. - * JSON.FORGET Documentation - */ - JSON_FORGET("json.forget", "json", false), - /** - * Gets the value at one or more paths in JSON serialized form. - * JSON.GET Documentation - */ - JSON_GET("json.get", "json", true), - /** - * Merges a given JSON value into matching paths. Consequently, JSON values at matching paths - * are updated, deleted, or expanded with new children. - * JSON.MERGE Documentation - */ - JSON_MERGE("json.merge", "json", false), - /** - * Returns the values at a path from one or more keys. - * JSON.MGET Documentation - */ - JSON_MGET("json.mget", "json", true), - /** - * Sets or updates the JSON value of one or more keys. - * JSON.MSET Documentation - */ - JSON_MSET("json.mset", "json", false), - /** - * Increments the numeric value at path by a value. - * JSON.NUMINCRBY Documentation - */ - JSON_NUMINCRBY("json.numincrby", "json", false), - /** - * Multiplies the numeric value at path by a value. - * JSON.NUMMULTBY Documentation - */ - JSON_NUMMULTBY("json.nummultby", "json", false), - /** - * Returns the key names of JSON objects at the paths matching a given path expression. - * JSON.OBJKEYS Documentation - */ - JSON_OBJKEYS("json.objkeys", "json", true), - /** - * Returns the number of keys in JSON objects at the paths matching a given path expression. - * JSON.OBJLEN Documentation - */ - JSON_OBJLEN("json.objlen", "json", true), - /** - * Returns the JSON value at path in Redis Serialization Protocol (RESP). - * JSON.RESP Documentation - */ - JSON_RESP("json.resp", "json", true), - /** - * Sets or updates the JSON value at a path. - * JSON.SET Documentation - */ - JSON_SET("json.set", "json", false), - /** - * Appends a string to JSON strings at the paths matching a given path expression. - * JSON.STRAPPEND Documentation - */ - JSON_STRAPPEND("json.strappend", "json", false), - /** - * Returns the length of JSON strings at the paths matching a given path expression. - * JSON.STRLEN Documentation - */ - JSON_STRLEN("json.strlen", "json", true), - /** - * Toggles a boolean value. - * JSON.TOGGLE Documentation - */ - JSON_TOGGLE("json.toggle", "json", false), - /** - * Returns the type of the JSON value at path. - * JSON.TYPE Documentation - */ - JSON_TYPE("json.type", "json", true), - /** - * Returns all keys matching pattern. - * KEYS Documentation - */ - KEYS("keys", "none", true), - /** - * Returns the Unix timestamp of the last successful save to disk. - * LASTSAVE Documentation - */ - LASTSAVE("lastsave", "server", false), - /** - * Container command for latency monitoring (LATEST, HISTORY, RESET, GRAPH, DOCTOR subcommands). - * LATENCY Documentation - */ - LATENCY("latency", "server", false), - /** - * Implements the longest common subsequence algorithm between the values stored at two keys. - * LCS Documentation - */ - LCS("lcs", "string", false), - /** - * Returns the element at index in the list stored at key. - * LINDEX Documentation - */ - LINDEX("lindex", "list", false), - /** - * Inserts element in the list stored at key either before or after the reference value pivot. - * LINSERT Documentation - */ - LINSERT("linsert", "list", false), - /** - * Returns the length of the list stored at key. - * LLEN Documentation - */ - LLEN("llen", "list", false), - /** - * Atomically returns and removes the first or last element of the list stored at source, and pushes it to the first or last position of the list stored at destination. - * LMOVE Documentation - */ - LMOVE("lmove", "list", false), - /** - * Pops one or more elements from the first non-empty list key from the list of provided key names. - * LMPOP Documentation - */ - LMPOP("lmpop", "list", false), - /** - * Displays a piece of generative computer art together with the Redis version. - * LOLWUT Documentation - */ - LOLWUT("lolwut", "server", false), - /** - * Removes and returns the first elements of the list stored at key. - * LPOP Documentation - */ - LPOP("lpop", "list", false), - /** - * Returns the index of matching elements inside a Redis list. - * LPOS Documentation - */ - LPOS("lpos", "list", false), - /** - * Insert all the specified values at the head of the list stored at key. - * LPUSH Documentation - */ - LPUSH("lpush", "list", false), - /** - * Inserts specified values at the head of the list stored at key, only if key already exists and holds a list. - * LPUSHX Documentation - */ - LPUSHX("lpushx", "list", false), - /** - * Returns the specified elements of the list stored at key, using zero-based start and stop indexes. - * LRANGE Documentation - */ - LRANGE("lrange", "list", false), - /** - * Removes the first count occurrences of elements equal to element from the list stored at key. - * LREM Documentation - */ - LREM("lrem", "list", false), - /** - * Sets the list element at index to value. - * LSET Documentation - */ - LSET("lset", "list", false), - /** - * Trim an existing list so that it will contain only the specified range of elements. - * LTRIM Documentation - */ - LTRIM("ltrim", "list", false), - /** - * Container command for memory introspection (DOCTOR, STATS, USAGE, MALLOC-STATS, PURGE subcommands). - * MEMORY Documentation - */ - MEMORY("memory", "server", false), - /** - * Returns the values of all specified keys, for every key that does not hold a string value a nil value is returned. - * MGET Documentation - */ - MGET("mget", "string", false), - /** - * Atomically transfer a key from a source Redis instance to a destination Redis instance. - * MIGRATE Documentation - */ - MIGRATE("migrate", "key", false), - /** - * Container command for module management (LIST, LOAD, UNLOAD subcommands). - * MODULE Documentation - */ - MODULE("module", "server", false), - /** - * Streams back every command processed by the Redis server, useful for debugging. - * MONITOR Documentation - */ - MONITOR("monitor", "server", false), - /** - * Moves key from the currently selected database to the specified destination database. - * MOVE Documentation - */ - MOVE("move", "key", false), - /** - * Sets the given keys to their respective values, atomically. - * MSET Documentation - */ - MSET("mset", "string", false), - /** - * Sets the given keys to their respective values, only if none of the keys exist. - * MSETNX Documentation - */ - MSETNX("msetnx", "string", false), - /** - * Marks the start of a transaction block. Subsequent commands will be queued for atomic execution using EXEC. - * MULTI Documentation + * Integer reply: the number of keys that were removed. + * DEL Documentation */ - MULTI("multi", "transaction", false), + DEL("del", "mixed", false), /** - * Container command for introspecting the internal representation of Redis objects (ENCODING, FREQ, IDLETIME, REFCOUNT subcommands). - * OBJECT Documentation + * Invoke the execution of a server-side Lua script. + * The return value depends on the script that was executed. + * EVAL Documentation */ - OBJECT("object", "key", false), + EVAL("eval", "script", false), /** - * Remove the existing timeout on key, turning the key from volatile to persistent. - * PERSIST Documentation + * Evaluate a script from the server's cache by its SHA1 digest. + * The return value depends on the script that was executed. + * EVALSHA Documentation */ - PERSIST("persist", "key", false), + EVALSHA("evalsha", "script", false), /** - * This command works exactly like EXPIRE but the time to live of the key is specified in milliseconds. - * PEXPIRE Documentation + * Returns if key exists. + * Integer reply: the number of keys that exist from those specified as arguments. + * EXISTS Documentation */ - PEXPIRE("pexpire", "key", false), + EXISTS("exists", "mixed", true), /** - * Has the same effect and semantics as EXPIREAT, but the Unix time at which the key will expire is specified in milliseconds. - * PEXPIREAT Documentation + * Runs a search query on an index and performs aggregate transformations on the results. + * FT.AGGREGATE Documentation */ - PEXPIREAT("pexpireat", "key", false), + FT_AGGREGATE("ft.aggregate", "search", true), /** - * Returns the absolute Unix timestamp in milliseconds at which the given key will expire. - * PEXPIRETIME Documentation + * Searches the index with a textual query, returning either documents or just ids. + * FT.SEARCH Documentation */ - PEXPIRETIME("pexpiretime", "key", false), + FT_SEARCH("ft.search", "search", true), /** - * Adds all the elements to the HyperLogLog data structure stored at the variable name specified as the key. - * PFADD Documentation + * Get the value of key. + * GET Documentation */ - PFADD("pfadd", "hyperloglog", false), + GET("get", "string", true), /** - * Returns the approximated cardinality of the set observed by the HyperLogLog at key. - * PFCOUNT Documentation + * Returns the value associated with field in the hash stored at key. + * HGET Documentation */ - PFCOUNT("pfcount", "hyperloglog", false), + HGET("hget", "hash", true), /** - * Merges multiple HyperLogLog values into a unique value that approximates the cardinality of the union of the observed sets. - * PFMERGE Documentation + * Returns all fields and values of the hash stored at key. + * HGETALL Documentation */ - PFMERGE("pfmerge", "hyperloglog", false), + HGETALL("hgetall", "hash", true), /** - * Returns PONG if no argument is provided, otherwise returns a copy of the argument as a bulk string. - * PING Documentation + * Sets the specified fields to their respective values in the hash stored at key. + * This command overwrites the values of specified fields that exist in the hash. + * If key doesn't exist, a new key holding a hash is created. + * HSET Documentation */ - PING("ping", "connection", false), + HSET("hset", "hash", false), /** - * Works exactly like SETEX with the sole difference that the expire time is specified in milliseconds instead of seconds. - * PSETEX Documentation + * Increments the number stored at key by one. + * If the key does not exist, it is set to 0 before performing the operation. + * An error is returned if the key contains a value of the wrong type + * or contains a string that can not be represented as integer. + * This operation is limited to 64-bit signed integers. + * INCR Documentation */ - PSETEX("psetex", "string", false), + INCR("incr", "string", false), /** - * Subscribes the client to the given patterns. - * PSUBSCRIBE Documentation + * Returns all keys matching pattern. + * KEYS Documentation */ - PSUBSCRIBE("psubscribe", "pubsub", false), + KEYS("keys", "none", true), /** - * Like TTL, but returns the remaining time to live of a key in milliseconds. - * PTTL Documentation + * Set key to hold the string value. If key already holds a value, it is overwritten, regardless of its type. + * Any previous time to live associated with the key is discarded on successful SET operation. + * SET Documentation */ - PTTL("pttl", "key", false), + SET("set", "string", false), /** * Posts a message to the given channel. * Integer reply: the number of clients that the message was sent to. * PUBLISH Documentation */ PUBLISH("publish", "pubsub", false), - /** - * Container command for introspecting the Pub/Sub subsystem state (CHANNELS, NUMSUB, NUMPAT subcommands). - * PUBSUB Documentation - */ - PUBSUB("pubsub", "pubsub", false), - /** - * Unsubscribes the client from the given patterns, or from all of them if none is given. - * PUNSUBSCRIBE Documentation - */ - PUNSUBSCRIBE("punsubscribe", "pubsub", false), - /** - * Return a random key from the currently selected database. - * RANDOMKEY Documentation - */ - RANDOMKEY("randomkey", "key", false), - /** - * Enables read queries for a connection to a Redis Cluster replica node. - * READONLY Documentation - */ - READONLY("readonly", "cluster", false), - /** - * Disables read queries for a connection to a Redis Cluster replica node, reverting READONLY. - * READWRITE Documentation - */ - READWRITE("readwrite", "cluster", false), - /** - * Renames key to newkey. It returns an error when key does not exist. - * RENAME Documentation - */ - RENAME("rename", "key", false), - /** - * Renames key to newkey if newkey does not yet exist. - * RENAMENX Documentation - */ - RENAMENX("renamenx", "key", false), - /** - * Configures the current instance as a replica of a master instance, or promotes an instance back to being a master. - * REPLICAOF Documentation - */ - REPLICAOF("replicaof", "cluster", false), - /** - * Performs a full reset of the connection's server-side context, discarding MULTI/WATCH state and subscriptions. - * RESET Documentation - */ - RESET("reset", "connection", false), - /** - * Create a key associated with a value that is obtained by deserializing the provided serialized value, obtained via DUMP. - * RESTORE Documentation - */ - RESTORE("restore", "key", false), - /** - * Returns the role of the instance in the context of replication, along with additional replication information. - * ROLE Documentation - */ - ROLE("role", "server", false), - /** - * Removes and returns the last elements of the list stored at key. - * RPOP Documentation - */ - RPOP("rpop", "list", false), - /** - * Atomically returns and removes the last element of the list stored at source, and pushes it to the front of the list stored at destination. - * RPOPLPUSH Documentation - */ - RPOPLPUSH("rpoplpush", "list", false), - /** - * Insert all the specified values at the tail of the list stored at key. - * RPUSH Documentation - */ - RPUSH("rpush", "list", false), - /** - * Inserts specified values at the tail of the list stored at key, only if key already exists and holds a list. - * RPUSHX Documentation - */ - RPUSHX("rpushx", "list", false), /** * Add the specified members to the set stored at key. * Specified members that are already a member of this set are ignored. @@ -972,134 +102,28 @@ public enum RedisCommandType { * SADD Documentation */ SADD("sadd", "set", false), - /** - * Performs a synchronous save of the dataset producing a point in time snapshot of all the data inside the Redis instance. - * SAVE Documentation - */ - SAVE("save", "server", false), - /** - * Iterates the set of keys in the currently selected database, cursor-based, without blocking the server. - * SCAN Documentation - */ - SCAN("scan", "key", false), - /** - * Returns the set cardinality (number of elements) of the set stored at key. - * SCARD Documentation - */ - SCARD("scard", "set", false), - /** - * Container command for script management (LOAD, EXISTS, FLUSH, KILL subcommands). - * SCRIPT Documentation - */ - SCRIPT("script", "script", false), - /** - * Returns the members of the set resulting from the difference between the first set and all the successive sets. - * SDIFF Documentation - */ - SDIFF("sdiff", "set", false), - /** - * Stores the members of the set resulting from the difference between the first set and all the successive sets in destination. - * SDIFFSTORE Documentation - */ - SDIFFSTORE("sdiffstore", "set", false), /** * Select the Redis logical database having the specified zero-based numeric index. * New connections always use the database 0. * SELECT Documentation */ SELECT("select", "none", false), - /** - * Container command for Redis Sentinel administration. - * SENTINEL Documentation - */ - SENTINEL("sentinel", "cluster", false), - /** - * Set key to hold the string value. If key already holds a value, it is overwritten, regardless of its type. - * Any previous time to live associated with the key is discarded on successful SET operation. - * SET Documentation - */ - SET("set", "string", false), - /** - * Sets or clears the bit at offset in the string value stored at key. - * SETBIT Documentation - */ - SETBIT("setbit", "string", false), /** * Set key to hold the string value and set key to timeout after a given number of seconds. * SETEX Documentation */ SETEX("setex", "string", false), - /** - * Set key to hold string value if key does not exist. - * SETNX Documentation - */ - SETNX("setnx", "string", false), - /** - * Overwrites part of the string stored at key, starting at the specified offset. - * SETRANGE Documentation - */ - SETRANGE("setrange", "string", false), - /** - * Synchronously saves the dataset to disk (if configured) and then shuts down the server. - * SHUTDOWN Documentation - */ - SHUTDOWN("shutdown", "server", false), /** * Returns the members of the set resulting from the intersection of all the given sets. * SINTER Documentation */ SINTER("sinter", "set", true), - /** - * Returns the cardinality of the set which would result from the intersection of all the given sets, without actually computing it. - * SINTERCARD Documentation - */ - SINTERCARD("sintercard", "set", false), - /** - * Stores the members of the set resulting from the intersection of all the given sets in destination. - * SINTERSTORE Documentation - */ - SINTERSTORE("sinterstore", "set", false), - /** - * Returns if member is a member of the set stored at key. - * SISMEMBER Documentation - */ - SISMEMBER("sismember", "set", false), - /** - * Deprecated alias for REPLICAOF, configures the current instance as a replica of a master instance, or promotes it to master. - * SLAVEOF Documentation - */ - SLAVEOF("slaveof", "cluster", false), - /** - * Container command for reading and resetting the Redis slow queries log (GET, LEN, RESET subcommands). - * SLOWLOG Documentation - */ - SLOWLOG("slowlog", "server", false), /** * Returns all the members of the set value stored at key. * This has the same effect as running SINTER with one argument key. * SMEMBERS Documentation */ SMEMBERS("smembers", "set", true), - /** - * Returns whether each member is a member of the set stored at key. - * SMISMEMBER Documentation - */ - SMISMEMBER("smismember", "set", false), - /** - * Moves member from the set at source to the set at destination. - * SMOVE Documentation - */ - SMOVE("smove", "set", false), - /** - * Returns or stores the elements contained in the list, set or sorted set at key, sorted or filtered as requested. - * SORT Documentation - */ - SORT("sort", "key", false), - /** - * Read-only variant of the SORT command. Refuses the STORE option and can safely be used in read-only replicas. - * SORT_RO Documentation - */ - SORT_RO("sort_ro", "key", false), /** * Removes and returns one or more random members from the set value store at key. * Nil reply: if the key does not exist. @@ -1108,16 +132,6 @@ public enum RedisCommandType { * SPOP Documentation */ SPOP("spop", "set", false), - /** - * Posts a message to the given shard channel. - * SPUBLISH Documentation - */ - SPUBLISH("spublish", "pubsub", false), - /** - * Returns one or more random members from the set value stored at key, without removing them. - * SRANDMEMBER Documentation - */ - SRANDMEMBER("srandmember", "set", false), /** * Remove the specified members from the set stored at key. * Specified members that are not a member of this set are ignored. @@ -1126,21 +140,6 @@ public enum RedisCommandType { * SREM Documentation */ SREM("srem", "set", false), - /** - * Iterates elements of a set, cursor-based, without blocking the server. - * SSCAN Documentation - */ - SSCAN("sscan", "set", false), - /** - * Subscribes the client to the specified shard channels. - * SSUBSCRIBE Documentation - */ - SSUBSCRIBE("ssubscribe", "pubsub", false), - /** - * Returns the length of the string value stored at key. - * STRLEN Documentation - */ - STRLEN("strlen", "string", false), /** * Subscribes the client to the specified channels. * When successful, this command doesn't return anything. @@ -1149,56 +148,6 @@ public enum RedisCommandType { * SUBSCRIBE Documentation */ SUBSCRIBE("subscribe", "pubsub", false), - /** - * Deprecated alias for GETRANGE, returns the substring of the string value stored at key. - * SUBSTR Documentation - */ - SUBSTR("substr", "string", false), - /** - * Returns the members of the set resulting from the union of all the given sets. - * SUNION Documentation - */ - SUNION("sunion", "set", false), - /** - * Stores the members of the set resulting from the union of all the given sets in destination. - * SUNIONSTORE Documentation - */ - SUNIONSTORE("sunionstore", "set", false), - /** - * Unsubscribes the client from the given shard channels, or from all of them if none is given. - * SUNSUBSCRIBE Documentation - */ - SUNSUBSCRIBE("sunsubscribe", "pubsub", false), - /** - * Swaps two Redis databases, so that immediately all the clients connected to a given database will see the data of the other database. - * SWAPDB Documentation - */ - SWAPDB("swapdb", "key", false), - /** - * Returns the current server time as a two items lists: a Unix timestamp and the amount of microseconds already elapsed in the current second. - * TIME Documentation - */ - TIME("time", "server", false), - /** - * Alters the last access time of the specified keys, returning the number of existing keys specified. - * TOUCH Documentation - */ - TOUCH("touch", "key", false), - /** - * Returns the remaining time to live of a key that has a timeout, in seconds. - * TTL Documentation - */ - TTL("ttl", "key", false), - /** - * Returns the string representation of the type of the value stored at key. - * TYPE Documentation - */ - TYPE("type", "key", false), - /** - * Removes the specified keys, like DEL, but performs the memory reclamation in a different thread, non-blocking. - * UNLINK Documentation - */ - UNLINK("unlink", "key", false), /** * Unsubscribes the client from the given channels, or from all of them if none is given. * When successful, this command doesn't return anything. @@ -1207,257 +156,6 @@ public enum RedisCommandType { * UNSUBSCRIBE Documentation */ UNSUBSCRIBE("unsubscribe", "pubsub", false), - /** - * Flushes all the previously watched keys for a transaction. - * UNWATCH Documentation - */ - UNWATCH("unwatch", "transaction", false), - /** - * Blocks the current client until all the previous write commands are successfully transferred and acknowledged by at least the specified number of replicas. - * WAIT Documentation - */ - WAIT("wait", "server", false), - /** - * Blocks the current client until all previous write commands are successfully written to the append-only file of the local and the specified number of replicas. - * WAITAOF Documentation - */ - WAITAOF("waitaof", "server", false), - /** - * Marks the given keys to be watched for conditional execution of a transaction. - * WATCH Documentation - */ - WATCH("watch", "transaction", false), - /** - * Removes one or multiple messages from the pending entries list of a stream consumer group. - * XACK Documentation - */ - XACK("xack", "stream", false), - /** - * Appends the specified stream entry to the stream at the specified key. - * XADD Documentation - */ - XADD("xadd", "stream", false), - /** - * Transfers ownership of pending stream entries that match the criteria to the specified consumer. - * XAUTOCLAIM Documentation - */ - XAUTOCLAIM("xautoclaim", "stream", false), - /** - * Changes the ownership of a pending message to a different consumer, without acknowledging it. - * XCLAIM Documentation - */ - XCLAIM("xclaim", "stream", false), - /** - * Removes the specified entries from a stream, and returns the number of entries deleted. - * XDEL Documentation - */ - XDEL("xdel", "stream", false), - /** - * Container command for consumer group management (CREATE, SETID, DESTROY, CREATECONSUMER, DELCONSUMER subcommands). - * XGROUP Documentation - */ - XGROUP("xgroup", "stream", false), - /** - * Container command for stream introspection (STREAM, GROUPS, CONSUMERS subcommands). - * XINFO Documentation - */ - XINFO("xinfo", "stream", false), - /** - * Returns the number of entries inside a stream. - * XLEN Documentation - */ - XLEN("xlen", "stream", false), - /** - * Fetches information about pending messages of a given consumer group. - * XPENDING Documentation - */ - XPENDING("xpending", "stream", false), - /** - * Returns the stream entries matching a given range of IDs. - * XRANGE Documentation - */ - XRANGE("xrange", "stream", false), - /** - * Reads data from one or multiple streams, only returning entries with an ID greater than the last received ID. - * XREAD Documentation - */ - XREAD("xread", "stream", false), - /** - * Reads messages from a stream via a consumer group, similarly to XREAD. - * XREADGROUP Documentation - */ - XREADGROUP("xreadgroup", "stream", false), - /** - * Like XRANGE, but returns entries in reverse order, and takes the range in reverse order. - * XREVRANGE Documentation - */ - XREVRANGE("xrevrange", "stream", false), - /** - * Trims the stream by evicting older entries if needed. - * XTRIM Documentation - */ - XTRIM("xtrim", "stream", false), - /** - * Adds all the specified members with the specified scores to the sorted set stored at key. - * ZADD Documentation - */ - ZADD("zadd", "zset", false), - /** - * Returns the sorted set cardinality (number of elements) of the sorted set stored at key. - * ZCARD Documentation - */ - ZCARD("zcard", "zset", false), - /** - * Returns the number of elements in the sorted set at key with a score between min and max. - * ZCOUNT Documentation - */ - ZCOUNT("zcount", "zset", false), - /** - * Computes the difference between the first and all successive sorted sets and returns the result. - * ZDIFF Documentation - */ - ZDIFF("zdiff", "zset", false), - /** - * Computes the difference between the first and all successive sorted sets and stores the result in destination. - * ZDIFFSTORE Documentation - */ - ZDIFFSTORE("zdiffstore", "zset", false), - /** - * Increments the score of member in the sorted set stored at key by increment. - * ZINCRBY Documentation - */ - ZINCRBY("zincrby", "zset", false), - /** - * Computes the intersection of the given sorted sets and returns the result. - * ZINTER Documentation - */ - ZINTER("zinter", "zset", false), - /** - * Returns the cardinality of the intersection of the given sorted sets, without actually computing it. - * ZINTERCARD Documentation - */ - ZINTERCARD("zintercard", "zset", false), - /** - * Computes the intersection of the given sorted sets and stores the result in destination. - * ZINTERSTORE Documentation - */ - ZINTERSTORE("zinterstore", "zset", false), - /** - * Returns the number of elements in the sorted set at key with a value between min and max, when all elements have the same score. - * ZLEXCOUNT Documentation - */ - ZLEXCOUNT("zlexcount", "zset", false), - /** - * Pops one or more elements, with the highest or lowest scores, from the first non-empty sorted set from the list of provided key names. - * ZMPOP Documentation - */ - ZMPOP("zmpop", "zset", false), - /** - * Returns the scores associated with the specified members in the sorted set stored at key. - * ZMSCORE Documentation - */ - ZMSCORE("zmscore", "zset", false), - /** - * Removes and returns up to count members with the highest scores in the sorted set stored at key. - * ZPOPMAX Documentation - */ - ZPOPMAX("zpopmax", "zset", false), - /** - * Removes and returns up to count members with the lowest scores in the sorted set stored at key. - * ZPOPMIN Documentation - */ - ZPOPMIN("zpopmin", "zset", false), - /** - * Returns one or more random members from the sorted set value stored at key. - * ZRANDMEMBER Documentation - */ - ZRANDMEMBER("zrandmember", "zset", false), - /** - * Returns the specified range of elements in the sorted set stored at key. - * ZRANGE Documentation - */ - ZRANGE("zrange", "zset", false), - /** - * Returns all the elements in the sorted set at key with a value between min and max, when all elements have the same score. - * ZRANGEBYLEX Documentation - */ - ZRANGEBYLEX("zrangebylex", "zset", false), - /** - * Returns all the elements in the sorted set at key with a score between min and max. - * ZRANGEBYSCORE Documentation - */ - ZRANGEBYSCORE("zrangebyscore", "zset", false), - /** - * Stores a range of members from the sorted set at source into a new sorted set at destination. - * ZRANGESTORE Documentation - */ - ZRANGESTORE("zrangestore", "zset", false), - /** - * Returns the rank of member in the sorted set stored at key, with the scores ordered from low to high. - * ZRANK Documentation - */ - ZRANK("zrank", "zset", false), - /** - * Removes the specified members from the sorted set stored at key. - * ZREM Documentation - */ - ZREM("zrem", "zset", false), - /** - * Removes all elements in the sorted set between the lexicographical range specified by min and max. - * ZREMRANGEBYLEX Documentation - */ - ZREMRANGEBYLEX("zremrangebylex", "zset", false), - /** - * Removes all elements in the sorted set stored at key with rank between start and stop. - * ZREMRANGEBYRANK Documentation - */ - ZREMRANGEBYRANK("zremrangebyrank", "zset", false), - /** - * Removes all elements in the sorted set stored at key with a score between min and max. - * ZREMRANGEBYSCORE Documentation - */ - ZREMRANGEBYSCORE("zremrangebyscore", "zset", false), - /** - * Returns the specified range of elements in the sorted set stored at key, ordered from the highest to the lowest score. - * ZREVRANGE Documentation - */ - ZREVRANGE("zrevrange", "zset", false), - /** - * Returns all the elements in the sorted set at key with a value between max and min, when all elements have the same score. - * ZREVRANGEBYLEX Documentation - */ - ZREVRANGEBYLEX("zrevrangebylex", "zset", false), - /** - * Returns all the elements in the sorted set at key with a score between max and min, ordered from high to low. - * ZREVRANGEBYSCORE Documentation - */ - ZREVRANGEBYSCORE("zrevrangebyscore", "zset", false), - /** - * Returns the rank of member in the sorted set stored at key, with the scores ordered from high to low. - * ZREVRANK Documentation - */ - ZREVRANK("zrevrank", "zset", false), - /** - * Iterates elements of a sorted set and their scores, cursor-based, without blocking the server. - * ZSCAN Documentation - */ - ZSCAN("zscan", "zset", false), - /** - * Returns the score of member in the sorted set stored at key. - * ZSCORE Documentation - */ - ZSCORE("zscore", "zset", false), - /** - * Computes the union of the given sorted sets and returns the result. - * ZUNION Documentation - */ - ZUNION("zunion", "zset", false), - /** - * Computes the union of the given sorted sets and stores the result in destination. - * ZUNIONSTORE Documentation - */ - ZUNIONSTORE("zunionstore", "zset", false), - /** * Default unregistered command value. */ From 864d0fbef1708f2d30e79ce94c3bb2a563b3c097 Mon Sep 17 00:00:00 2001 From: Alexander Szyrej Date: Wed, 16 Sep 2026 00:47:11 -0300 Subject: [PATCH 5/5] tests refactor using FT.SEARCH --- .../redis/JedisOperationsImpl.java | 19 +++++++--- .../ConnectionClassReplacementTest.java | 35 ++++++------------ .../example/redis/JedisInstrumentedTest.java | 36 ++++++------------- .../example/redis/JedisOperations.java | 5 +-- 4 files changed, 40 insertions(+), 55 deletions(-) diff --git a/client-java/instrumentation/src/test/java/com/foo/somedifferentpackage/examples/methodreplacement/redis/JedisOperationsImpl.java b/client-java/instrumentation/src/test/java/com/foo/somedifferentpackage/examples/methodreplacement/redis/JedisOperationsImpl.java index eb56763a12..165fdf8f91 100644 --- a/client-java/instrumentation/src/test/java/com/foo/somedifferentpackage/examples/methodreplacement/redis/JedisOperationsImpl.java +++ b/client-java/instrumentation/src/test/java/com/foo/somedifferentpackage/examples/methodreplacement/redis/JedisOperationsImpl.java @@ -3,6 +3,11 @@ import org.evomaster.client.java.instrumentation.example.redis.JedisOperations; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.UnifiedJedis; +import redis.clients.jedis.search.FTCreateParams; +import redis.clients.jedis.search.schemafields.SchemaField; +import redis.clients.jedis.search.schemafields.TextField; + +import java.util.Collections; /** * {@link JedisOperations} implementation backed by a real {@link UnifiedJedis} connection, @@ -22,12 +27,18 @@ public String get(String key) { } @Override - public Object jsonGet(String key) { - return jedis.jsonGet(key); + public void ftCreate(String index, String prefix, String textField) { + FTCreateParams params = FTCreateParams.createParams().prefix(prefix); + jedis.ftCreate(index, params, Collections.singletonList(TextField.of(textField))); + } + + @Override + public void hset(String key, String field, String value) { + jedis.hset(key, field, value); } @Override - public void jsonSet(String key, Object value) { - jedis.jsonSet(key, value); + public long ftSearch(String index, String query) { + return jedis.ftSearch(index, query).getTotalResults(); } } diff --git a/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/thirdpartyclasses/ConnectionClassReplacementTest.java b/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/thirdpartyclasses/ConnectionClassReplacementTest.java index 436150530f..3cdd763eb1 100644 --- a/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/thirdpartyclasses/ConnectionClassReplacementTest.java +++ b/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/coverage/methodreplacement/thirdpartyclasses/ConnectionClassReplacementTest.java @@ -7,10 +7,7 @@ import redis.clients.jedis.CommandObject; import redis.clients.jedis.Connection; import redis.clients.jedis.Protocol; -import redis.clients.jedis.args.RawableFactory; -import redis.clients.jedis.commands.ProtocolCommand; import redis.clients.jedis.search.SearchProtocol; -import redis.clients.jedis.util.SafeEncoder; import java.util.List; @@ -29,21 +26,6 @@ public void setup() { mockConnection = mock(Connection.class); } - private enum FakeJsonCommand implements ProtocolCommand { - GET("JSON.GET"); - - private final byte[] raw; - - FakeJsonCommand(String alt) { - raw = SafeEncoder.encode(alt); - } - - @Override - public byte[] getRaw() { - return raw; - } - } - @Test public void testExecuteCommandCoreGet() { String key = "foo"; @@ -63,10 +45,15 @@ public void testExecuteCommandCoreGet() { } @Test - public void testExecuteCommandJsonGet() { - String key = "mykey"; - CommandArguments args = new CommandArguments(FakeJsonCommand.GET) - .add(RawableFactory.from(key)); + public void testExecuteCommandFtAggregate() { + String indexName = "myIndex"; + String query = "*"; + CommandArguments args = new CommandArguments(SearchProtocol.SearchCommand.AGGREGATE) + .add(indexName) + .add(query) + .add("GROUPBY") + .add("1") + .add("@category"); CommandObject commandObject = new CommandObject<>(args, null); ConnectionClassReplacement.executeCommand(mockConnection, commandObject); @@ -77,8 +64,8 @@ public void testExecuteCommandJsonGet() { org.evomaster.client.java.instrumentation.RedisCommand redisCmd = infoList.get(0).getRedisCommandData().iterator().next(); - assertEquals("JSON_GET", redisCmd.getType().name()); - assertArrayEquals(new String[]{key}, redisCmd.getArgs()); + assertEquals("FT_AGGREGATE", redisCmd.getType().name()); + assertArrayEquals(new String[]{indexName, query, "GROUPBY", "1", "@category"}, redisCmd.getArgs()); } @Test diff --git a/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/example/redis/JedisInstrumentedTest.java b/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/example/redis/JedisInstrumentedTest.java index 649e8bd970..d487033988 100644 --- a/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/example/redis/JedisInstrumentedTest.java +++ b/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/example/redis/JedisInstrumentedTest.java @@ -18,15 +18,14 @@ public class JedisInstrumentedTest { private static final int REDIS_PORT = 6379; - // redis-stack-server, not plain redis, so the JSON module is loaded - // server-side and JSON.GET/JSON.SET don't error out + // redis-stack-server, not plain redis, so the RediSearch module is loaded + // server-side and FT.CREATE/FT.SEARCH don't error out private static final GenericContainer redisContainer = new GenericContainer<>("redis/redis-stack-server:latest") .withExposedPorts(REDIS_PORT); private static final String GET = "GET"; - private static final String JSON_GET = "JSON_GET"; - private static final String JSON_SET = "JSON_SET"; + private static final String FT_SEARCH = "FT_SEARCH"; @BeforeAll public static void setupAll() { @@ -73,36 +72,23 @@ public void testGetInstrumentationWithClassLoader() throws Exception { } @Test - public void testJsonGetInstrumentationWithClassLoader() throws Exception { + public void testFtSearchInstrumentationWithClassLoader() throws Exception { ExecutionTracer.reset(); JedisOperations jedisInstrumented = getInstance(); - jedisInstrumented.jsonGet("foo"); + jedisInstrumented.ftCreate("idx:products", "product:", "title"); + jedisInstrumented.hset("product:1", "title", "redis handbook"); + long total = jedisInstrumented.ftSearch("idx:products", "@title:redis"); - List infoList = ExecutionTracer.exposeAdditionalInfoList(); - assertFalse(infoList.isEmpty(), "Expected Redis instrumentation data"); - - boolean foundJsonGet = infoList.stream() - .flatMap(i -> i.getRedisCommandData().stream()) - .anyMatch(cmd -> cmd.getType().name().equals(JSON_GET)); - - assertTrue(foundJsonGet, "Expected a JSON.GET command to be instrumented via ConnectionClassReplacement"); - } - - @Test - public void testJsonSetInstrumentationWithClassLoader() throws Exception { - ExecutionTracer.reset(); - - JedisOperations jedisInstrumented = getInstance(); - jedisInstrumented.jsonSet("fooSet", "{\"field\":\"bar\"}"); + assertEquals(1, total, "Expected the indexed document to be found by FT.SEARCH"); List infoList = ExecutionTracer.exposeAdditionalInfoList(); assertFalse(infoList.isEmpty(), "Expected Redis instrumentation data"); - boolean foundJsonSet = infoList.stream() + boolean foundFtSearch = infoList.stream() .flatMap(i -> i.getRedisCommandData().stream()) - .anyMatch(cmd -> cmd.getType().name().equals(JSON_SET)); + .anyMatch(cmd -> cmd.getType().name().equals(FT_SEARCH)); - assertTrue(foundJsonSet, "Expected a JSON.SET command to be instrumented via ConnectionClassReplacement"); + assertTrue(foundFtSearch, "Expected an FT.SEARCH command to be instrumented via ConnectionClassReplacement"); } } diff --git a/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/example/redis/JedisOperations.java b/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/example/redis/JedisOperations.java index c49850d11f..6b1b2e143e 100644 --- a/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/example/redis/JedisOperations.java +++ b/client-java/instrumentation/src/test/java/org/evomaster/client/java/instrumentation/example/redis/JedisOperations.java @@ -6,6 +6,7 @@ */ public interface JedisOperations { String get(String key); - Object jsonGet(String key); - void jsonSet(String key, Object value); + void ftCreate(String index, String prefix, String textField); + void hset(String key, String field, String value); + long ftSearch(String index, String query); }