From 7e46b1e2d5a6fdabc7c712b8e2f79d6b2be63355 Mon Sep 17 00:00:00 2001 From: Alexander Szyrej Date: Thu, 6 Nov 2025 19:08:57 -0300 Subject: [PATCH 1/9] added calls to taint handler when comparing keys and regex --- .../redis/RedisHeuristicsCalculator.java | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisHeuristicsCalculator.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisHeuristicsCalculator.java index 79085258cd..703d0d481d 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisHeuristicsCalculator.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisHeuristicsCalculator.java @@ -89,8 +89,12 @@ private RedisDistanceWithMetrics calculateDistanceForPattern( return new RedisDistanceWithMetrics(MAX_REDIS_DISTANCE, 0); } for (RedisInfo k : keys) { + String key = k.getKey(); double d = TruthnessUtils.normalizeValue( - RegexDistanceUtils.getStandardDistance(k.getKey(), redisPatternToRegex(pattern))); + RegexDistanceUtils.getStandardDistance(key, regex)); + if (taintHandler != null) { + taintHandler.handleTaintForRegex(key, regex); + } minDist = Math.min(minDist, d); eval++; if (d == 0) return new RedisDistanceWithMetrics(0, eval); @@ -119,8 +123,12 @@ private RedisDistanceWithMetrics calculateDistanceForKeyMatch( for (RedisInfo k : candidateKeys) { try { - long rawDist = DistanceHelper.getLeftAlignmentDistance(targetKey, k.getKey()); + String key = k.getKey(); + long rawDist = DistanceHelper.getLeftAlignmentDistance(targetKey, key); double normDist = TruthnessUtils.normalizeValue(rawDist); + if (taintHandler != null) { + taintHandler.handleTaintForStringEquals(targetKey, key, false); + } minDist = Math.min(minDist, normDist); evaluated++; @@ -155,12 +163,13 @@ private RedisDistanceWithMetrics calculateDistanceForFieldInHash( for (RedisInfo k : keys) { try { - long keyDist = DistanceHelper.getLeftAlignmentDistance(targetKey, k.getKey()); - + String key = k.getKey(); + long keyDist = DistanceHelper.getLeftAlignmentDistance(targetKey, key); double fieldDist = k.hasField() ? 0d : MAX_REDIS_DISTANCE; - double combined = TruthnessUtils.normalizeValue(keyDist + fieldDist); - + if (taintHandler != null) { + taintHandler.handleTaintForStringEquals(targetKey, key, false); + } minDist = Math.min(minDist, combined); evaluated++; @@ -237,6 +246,9 @@ private double computeSetIntersectionDistance(Set s1, Set s2) { for (String a : s1) { for (String b : s2) { long raw = DistanceHelper.getLeftAlignmentDistance(a, b); + if (taintHandler != null) { + taintHandler.handleTaintForStringEquals(a, b, false); + } double norm = TruthnessUtils.normalizeValue(raw); min = Math.min(min, norm); if (min == 0) return 0; From 4098b477403cb98fcd9b5a861a648f3761db451e Mon Sep 17 00:00:00 2001 From: Alexander Szyrej Date: Mon, 15 Dec 2025 01:13:45 -0300 Subject: [PATCH 2/9] Redis e2e test, starting with only GET and SET commands # Conflicts: # .gitignore # core-tests/e2e-tests/pom.xml --- .../api/dto/ExtraHeuristicEntryDto.java | 4 +- .../controller/internal/EMController.java | 1 + .../controller/internal/SutController.java | 53 +++++++- .../internal/db/redis/RedisHandler.java | 26 +--- .../java/controller/redis/RedisClient.java | 15 ++- .../redis/RedisHeuristicsCalculator.java | 34 ++++- .../java/controller/redis/RedisInfo.java | 15 +-- .../db/redis/RedisHandlerIntegrationTest.java | 1 - .../internal/db/redis/RedisHandlerTest.java | 1 - .../redis/RedisHeuristicsCalculatorTest.java | 40 +++++- .../java/instrumentation/RedisCommand.java | 11 ++ .../StatefulConnectionClassReplacement.java | 7 -- .../e2e-tests/spring-rest-redis/pom.xml | 114 +++++++++++++++++ .../java/com/redis/SwaggerConfiguration.java | 38 ++++++ .../com/redis/lettuce/RedisLettuceApp.java | 20 +++ .../redis/lettuce/RedisLettuceController.java | 54 ++++++++ .../spring/rest/redis/RedisController.java | 119 ++++++++++++++++++ .../lettuce/RedisLettuceAppController.java | 15 +++ .../rest/redis/RedisControllerTest.java | 15 +++ .../redis/lettuce/RedisLettuceEMTest.java | 46 +++++++ .../kotlin/org/evomaster/core/EMConfig.kt | 11 ++ .../enterprise/service/EnterpriseFitness.kt | 38 +++++- .../core/search/service/Statistics.kt | 21 ++++ 23 files changed, 646 insertions(+), 53 deletions(-) create mode 100644 core-tests/e2e-tests/spring-rest-redis/pom.xml create mode 100644 core-tests/e2e-tests/spring-rest-redis/src/main/java/com/redis/SwaggerConfiguration.java create mode 100644 core-tests/e2e-tests/spring-rest-redis/src/main/java/com/redis/lettuce/RedisLettuceApp.java create mode 100644 core-tests/e2e-tests/spring-rest-redis/src/main/java/com/redis/lettuce/RedisLettuceController.java create mode 100644 core-tests/e2e-tests/spring-rest-redis/src/test/java/com/foo/spring/rest/redis/RedisController.java create mode 100644 core-tests/e2e-tests/spring-rest-redis/src/test/java/com/foo/spring/rest/redis/lettuce/RedisLettuceAppController.java create mode 100644 core-tests/e2e-tests/spring-rest-redis/src/test/java/org/evomaster/e2etests/spring/rest/redis/RedisControllerTest.java create mode 100644 core-tests/e2e-tests/spring-rest-redis/src/test/java/org/evomaster/e2etests/spring/rest/redis/lettuce/RedisLettuceEMTest.java diff --git a/client-java/controller-api/src/main/java/org/evomaster/client/java/controller/api/dto/ExtraHeuristicEntryDto.java b/client-java/controller-api/src/main/java/org/evomaster/client/java/controller/api/dto/ExtraHeuristicEntryDto.java index 578199ea95..2a089f3ff3 100644 --- a/client-java/controller-api/src/main/java/org/evomaster/client/java/controller/api/dto/ExtraHeuristicEntryDto.java +++ b/client-java/controller-api/src/main/java/org/evomaster/client/java/controller/api/dto/ExtraHeuristicEntryDto.java @@ -9,9 +9,9 @@ public class ExtraHeuristicEntryDto implements Serializable { /** * The type of extra heuristic. - * Note: for the moment, we only have heuristics on SQL, MONGO and OPENSEARCH commands + * Note: for the moment, we only have heuristics on SQL, MONGO, OPENSEARCH and REDIS commands */ - public enum Type {SQL, MONGO, OPENSEARCH} + public enum Type {SQL, MONGO, OPENSEARCH, REDIS} /** * Should we try to minimize or maximize the heuristic? diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/internal/EMController.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/internal/EMController.java index ea08188418..7533738464 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/internal/EMController.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/internal/EMController.java @@ -388,6 +388,7 @@ public Response runSut(SutRunDto dto, @Context HttpServletRequest httpServletReq noKillSwitch(() -> sutController.registerOrExecuteInitSqlCommandsIfNeeded(true)); noKillSwitch(() -> sutController.initMongoHandler()); noKillSwitch(() -> sutController.initOpenSearchHandler()); + noKillSwitch(() -> sutController.initRedisHandler()); } else { //TODO as starting should be blocking, need to check //if initialized, and wait if not diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/internal/SutController.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/internal/SutController.java index e6f64b89bf..bc68ce9ec8 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/internal/SutController.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/internal/SutController.java @@ -29,6 +29,7 @@ import org.evomaster.client.java.controller.api.dto.problem.rpc.*; import org.evomaster.client.java.controller.api.dto.problem.rpc.RPCTestDto; import org.evomaster.client.java.controller.internal.db.OpenSearchHandler; +import org.evomaster.client.java.controller.internal.db.redis.RedisHandler; import org.evomaster.client.java.sql.DbCleaner; import org.evomaster.client.java.sql.SqlScriptRunner; import org.evomaster.client.java.sql.SqlScriptRunnerCached; @@ -90,6 +91,8 @@ public abstract class SutController implements SutHandler, CustomizationHandler private final OpenSearchHandler openSearchHandler = new OpenSearchHandler(); + private final RedisHandler redisHandler = new RedisHandler(); + private Server controllerServer; /** @@ -346,6 +349,17 @@ public final void initOpenSearchHandler() { } } + public final void initRedisHandler() { + Object connection = getRedisConnection(); + redisHandler.setRedisClient(connection); + + List list = getAdditionalInfoList(); + if (!list.isEmpty()) { + AdditionalInfo last = list.get(list.size() - 1); + last.getRedisCommandData().forEach(redisHandler::handle); + } + } + /** * TODO further handle multiple connections * @return sql connection if there exists @@ -388,7 +402,8 @@ public final ExtraHeuristicsDto computeExtraHeuristics(boolean queryFromDatabase ExtraHeuristicsDto dto = new ExtraHeuristicsDto(); - if (isSQLHeuristicsComputationAllowed() || isMongoHeuristicsComputationAllowed() || isOpenSearchHeuristicsComputationAllowed()) { + if (isSQLHeuristicsComputationAllowed() || isMongoHeuristicsComputationAllowed() + || isOpenSearchHeuristicsComputationAllowed() || isRedisHeuristicsComputationAllowed()) { List additionalInfoList = getAdditionalInfoList(); if (isSQLHeuristicsComputationAllowed()) { @@ -397,10 +412,12 @@ public final ExtraHeuristicsDto computeExtraHeuristics(boolean queryFromDatabase if (isMongoHeuristicsComputationAllowed()) { computeMongoHeuristics(dto, additionalInfoList); } - if (isOpenSearchHeuristicsComputationAllowed()) { computeOpenSearchHeuristics(dto, additionalInfoList); } + if (isRedisHeuristicsComputationAllowed()) { + computeRedisHeuristics(dto, additionalInfoList); + } } return dto; } @@ -417,6 +434,10 @@ private boolean isOpenSearchHeuristicsComputationAllowed() { return openSearchHandler.isCalculateHeuristics(); } + private boolean isRedisHeuristicsComputationAllowed() { + return redisHandler.isCalculateHeuristics(); + } + private void computeSQLHeuristics(ExtraHeuristicsDto dto, List additionalInfoList, boolean queryFromDatabase) { /* TODO refactor, once we move SQL analysis into Core @@ -528,6 +549,34 @@ public final void computeOpenSearchHeuristics(ExtraHeuristicsDto dto, List additionalInfoList){ + if(redisHandler.isCalculateHeuristics()){ + if(!additionalInfoList.isEmpty()) { + AdditionalInfo last = additionalInfoList.get(additionalInfoList.size() - 1); + last.getRedisCommandData().forEach(it -> { + try { + redisHandler.handle(it); + } catch (Exception e){ + SimpleLogger.error("FAILED TO HANDLE REDIS COMMAND", e); + assert false; + } + }); + } + + redisHandler.getEvaluatedRedisCommands().stream() + .map(p -> + new ExtraHeuristicEntryDto( + ExtraHeuristicEntryDto.Type.REDIS, + ExtraHeuristicEntryDto.Objective.MINIMIZE_TO_ZERO, + p.getRedisCommand().toString(), + p.getRedisDistanceWithMetrics().getDistance(), + p.getRedisDistanceWithMetrics().getNumberOfEvaluatedKeys(), + false + )) + .forEach(h -> dto.heuristics.add(h)); + } + } + /** * handle specified init sql script after SUT is started. */ diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/internal/db/redis/RedisHandler.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/internal/db/redis/RedisHandler.java index bc737713a7..1bc8746cc8 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/internal/db/redis/RedisHandler.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/internal/db/redis/RedisHandler.java @@ -31,15 +31,10 @@ public class RedisHandler { */ private volatile boolean calculateHeuristics; - /** - * Whether to use execution's info or not - */ - private volatile boolean extractRedisExecution; - /** * The client must be created through a connection factory. */ - private RedisClient redisClient = null; + private Object redisClient = null; private final RedisHeuristicsCalculator calculator = new RedisHeuristicsCalculator(new TaintHandlerExecutionTracer()); @@ -49,7 +44,6 @@ public class RedisHandler { public RedisHandler() { operations = new ArrayList<>(); - extractRedisExecution = true; calculateHeuristics = true; } @@ -62,29 +56,19 @@ public boolean isCalculateHeuristics() { return calculateHeuristics; } - public boolean isExtractRedisExecution() { - return extractRedisExecution; - } - public void setCalculateHeuristics(boolean calculateHeuristics) { this.calculateHeuristics = calculateHeuristics; } - public void setExtractRedisExecution(boolean extractRedisExecution) { - this.extractRedisExecution = extractRedisExecution; - } - public void handle(RedisCommand info) { - if (extractRedisExecution) { - operations.add(info); - } + operations.add(info); } public List getEvaluatedRedisCommands() { operations.stream() .filter(command -> command.getType().shouldCalculateHeuristic()) .forEach(redisCommand -> { - RedisDistanceWithMetrics distanceWithMetrics = computeDistance(redisCommand, redisClient); + RedisDistanceWithMetrics distanceWithMetrics = computeDistance(redisCommand, (RedisClient) redisClient); evaluatedRedisCommands.add(new RedisCommandEvaluation(redisCommand, distanceWithMetrics)); }); operations.clear(); @@ -165,11 +149,11 @@ private List createRedisInfoForKeysByType(String type, RedisClient re private List createRedisInfoForKeysByField(String field, RedisClient redisClient) { Set keys = redisClient.getKeysByType(REDIS_HASH_TYPE); List redisData = new ArrayList<>(); - keys.forEach(key -> redisData.add(new RedisInfo(key, redisClient.hashFieldExists(key, field)))); + keys.forEach(key -> redisData.add(new RedisInfo(key, redisClient.getHashFields(key)))); return redisData; } - public void setRedisClient(RedisClient redisClient) { + public void setRedisClient(Object redisClient) { this.redisClient = redisClient; } } diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisClient.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisClient.java index 2969e17b46..ea30467dbf 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisClient.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisClient.java @@ -1,5 +1,7 @@ package org.evomaster.client.java.controller.redis; +import org.evomaster.client.java.utils.SimpleLogger; + import java.lang.reflect.Method; import java.util.*; import java.util.stream.Collectors; @@ -22,6 +24,8 @@ public RedisClient(String host, int port) { Method createUri = redisURIClass.getMethod("create", String.class); Object uri = createUri.invoke(null, "redis://" + host + ":" + port); + SimpleLogger.debug("Connecting to Redis with PORT: " + port); + Method createClient = redisClientClass.getMethod("create", redisURIClass); this.redisClient = createClient.invoke(null, uri); @@ -79,12 +83,6 @@ public void hashSet(String key, String field, String value) { invoke("hset", key, field, value); } - /** HEXISTS key field */ - public boolean hashFieldExists(String key, String field) { - Object result = invoke("hexists", key, field); - return result instanceof Boolean && (Boolean) result; - } - /** SMEMBERS key */ public Set getSetMembers(String key) { Object result = invoke("smembers", key); @@ -127,4 +125,9 @@ public Set getKeysByType(String expectedType) { public void flushAll() { invoke("flushall"); } + + public Map getHashFields(String key) { + Object result = invoke("hgetall", key); + return (Map) result; + } } \ No newline at end of file diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisHeuristicsCalculator.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisHeuristicsCalculator.java index 703d0d481d..1c5917a01b 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisHeuristicsCalculator.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisHeuristicsCalculator.java @@ -53,7 +53,8 @@ public RedisDistanceWithMetrics computeDistance(RedisCommand redisCommand, List< case HGET: { String key = redisCommand.extractArgs().get(0); - return calculateDistanceForFieldInHash(key, redisInfo); + String field = redisCommand.extractArgs().get(1); + return calculateDistanceForFieldInHash(key, field, redisInfo); } case SINTER: { @@ -152,6 +153,7 @@ private RedisDistanceWithMetrics calculateDistanceForKeyMatch( */ private RedisDistanceWithMetrics calculateDistanceForFieldInHash( String targetKey, + String targetField, List keys ) { if (keys.isEmpty()) { @@ -165,7 +167,7 @@ private RedisDistanceWithMetrics calculateDistanceForFieldInHash( try { String key = k.getKey(); long keyDist = DistanceHelper.getLeftAlignmentDistance(targetKey, key); - double fieldDist = k.hasField() ? 0d : MAX_REDIS_DISTANCE; + double fieldDist = calculateDistanceForField(targetField, k.getFields().keySet()); double combined = TruthnessUtils.normalizeValue(keyDist + fieldDist); if (taintHandler != null) { taintHandler.handleTaintForStringEquals(targetKey, key, false); @@ -184,6 +186,34 @@ private RedisDistanceWithMetrics calculateDistanceForFieldInHash( return new RedisDistanceWithMetrics(minDist, evaluated); } + /** + * Computes the distance of target field to each field in hash. + * + * @param targetField Field searched in query. + * @param fields Fields in hash. + * @return double + */ + private double calculateDistanceForField(String targetField, Set fields) { + if (fields.isEmpty()) { + return Long.MAX_VALUE; + } + + double minDist = Long.MAX_VALUE; + + for (String field : fields) { + try { + long fieldDist = DistanceHelper.getLeftAlignmentDistance(targetField, field); + if (taintHandler != null) { + taintHandler.handleTaintForStringEquals(targetField, field, false); + } + minDist = Math.min(minDist, fieldDist); + } catch (Exception ex) { + SimpleLogger.uniqueWarn("Failed FIELD distance on " + targetField + ": " + ex.getMessage()); + } + } + return minDist; + } + /** * Computes the distance of a given intersection considering the keys for the given sets. * diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisInfo.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisInfo.java index 51c7fa2a41..df3f531d6d 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisInfo.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisInfo.java @@ -1,5 +1,6 @@ package org.evomaster.client.java.controller.redis; +import java.util.Map; import java.util.Set; /** @@ -10,16 +11,16 @@ public class RedisInfo { private String key; private String type; - private boolean hasField; + private Map fields; private Set members; public RedisInfo(String key) { this.key = key; } - public RedisInfo(String key, boolean hasField) { + public RedisInfo(String key, Map fields) { this.key = key; - this.hasField = hasField; + this.fields = fields; } public RedisInfo(String key, String type, Set members) { @@ -36,11 +37,11 @@ public String getType() { return type; } - public boolean hasField() { - return hasField; - } - public Set getMembers() { return members; } + + public Map getFields() { + return fields; + } } 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 3bf0baa234..ce1138dda0 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 @@ -35,7 +35,6 @@ void setupHandler() { handler = new RedisHandler(); handler.setRedisClient(client); handler.setCalculateHeuristics(true); - handler.setExtractRedisExecution(true); client.flushAll(); } diff --git a/client-java/controller/src/test/java/org/evomaster/client/java/controller/internal/db/redis/RedisHandlerTest.java b/client-java/controller/src/test/java/org/evomaster/client/java/controller/internal/db/redis/RedisHandlerTest.java index 023adc89b4..475e45f465 100644 --- a/client-java/controller/src/test/java/org/evomaster/client/java/controller/internal/db/redis/RedisHandlerTest.java +++ b/client-java/controller/src/test/java/org/evomaster/client/java/controller/internal/db/redis/RedisHandlerTest.java @@ -28,7 +28,6 @@ void testHandleStoresCommands() { ); handler.handle(cmd); - assertTrue(handler.isExtractRedisExecution()); List evals = handler.getEvaluatedRedisCommands(); assertNotNull(evals); 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 26c3fa7a02..3ef2045220 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 @@ -93,8 +93,8 @@ void testHGetFieldExists() { ); List redisInfoList = new ArrayList<>(); - redisInfoList.add(new RedisInfo("profile", true)); - redisInfoList.add(new RedisInfo("users", false)); + redisInfoList.add(new RedisInfo("profile", Collections.singletonMap("name", "John"))); + redisInfoList.add(new RedisInfo("users", Collections.emptyMap())); RedisDistanceWithMetrics result = calculator.computeDistance(cmd, redisInfoList); @@ -113,7 +113,7 @@ void testHGetFieldNotExists() { ); List redisInfoList = new ArrayList<>(); - redisInfoList.add(new RedisInfo("profile", false)); + redisInfoList.add(new RedisInfo("profile", Collections.emptyMap())); RedisDistanceWithMetrics result = calculator.computeDistance(cmd, redisInfoList); @@ -121,6 +121,40 @@ void testHGetFieldNotExists() { assertTrue(result.getNumberOfEvaluatedKeys() >= 1); } + @Test + void testHGetFieldDistance() { + RedisCommand lowerDistanceCmd = new RedisCommand( + RedisCommand.RedisCommandType.HGET, + new String[]{"key", "key"}, + true, + 3 + ); + RedisCommand cmd = new RedisCommand( + RedisCommand.RedisCommandType.HGET, + new String[]{"key", "key"}, + true, + 3 + ); + RedisCommand greaterDistanceCmd = new RedisCommand( + RedisCommand.RedisCommandType.HGET, + new String[]{"key", "key"}, + true, + 3 + ); + + List redisInfoList = new ArrayList<>(); + redisInfoList.add(new RedisInfo("profile", Collections.singletonMap("height", "175"))); + + RedisDistanceWithMetrics resultLower = calculator.computeDistance(lowerDistanceCmd, redisInfoList); + RedisDistanceWithMetrics result = calculator.computeDistance(cmd, redisInfoList); + RedisDistanceWithMetrics resultGreater = calculator.computeDistance(greaterDistanceCmd, redisInfoList); + + assertTrue(resultLower.getDistance() < result.getDistance(), + "Closer target field should yield lower distance"); + assertTrue(result.getDistance() < resultGreater.getDistance(), + "Closer target key and field should yield lower distance"); + } + /** * Distance in intersection between two given sets: * - setA y setB share members → low distance 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 abe10e088e..f50ab6fae3 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 @@ -60,6 +60,13 @@ public enum RedisCommandType { * This operation is limited to 64-bit signed integers. * INCR Documentation */ + HSET("hset", "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 + */ INCR("incr", "string", false), /** * Returns all keys matching pattern. @@ -216,4 +223,8 @@ public boolean getSuccessfullyExecuted() { public long getExecutionTime() { return executionTime; } + + public String toString(){ + return this.getType().getLabel() + " " + String.join(" ", this.getArgs()); + } } 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 7880dc10b8..8fe78e2be3 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 @@ -72,13 +72,6 @@ public static Object dispatch(Object redis, @ThirdPartyCast(actualType = "io.let } } - private static String stripKey(String token) { - if (token != null && token.startsWith("key<") && token.endsWith(">")) { - return token.substring(4, token.length() - 1); - } - return token; - } - private static void addRedisCommand(RedisCommand.RedisCommandType type, String[] args, long executionTime) { RedisCommand cmd = new RedisCommand( type, diff --git a/core-tests/e2e-tests/spring-rest-redis/pom.xml b/core-tests/e2e-tests/spring-rest-redis/pom.xml new file mode 100644 index 0000000000..bd74c3af06 --- /dev/null +++ b/core-tests/e2e-tests/spring-rest-redis/pom.xml @@ -0,0 +1,114 @@ + + + 4.0.0 + + evomaster-e2e-tests + org.evomaster + 4.0.1-SNAPSHOT + + + evomaster-e2e-tests-spring-rest-redis + jar + + + + org.evomaster + evomaster-e2e-tests-utils + test-jar + + + org.evomaster + evomaster-client-java-controller + + + org.evomaster + evomaster-core + test + + + org.evomaster + evomaster-client-java-instrumentation + test-jar + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-params + test + + + org.springframework.boot + spring-boot-starter-web + + + javax.validation + validation-api + 2.0.1.Final + + + org.testcontainers + testcontainers + + + org.springframework.boot + spring-boot-starter-data-redis + + + redis.clients + jedis + 5.1.0 + + + org.testcontainers + junit-jupiter + 1.17.6 + test + + + io.springfox + springfox-swagger2 + + + io.swagger + * + + + + + io.rest-assured + rest-assured + + + org.springframework.boot + spring-boot-starter-security + + + + + + + + kotlin-maven-plugin + org.jetbrains.kotlin + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.apache.maven.plugins + maven-surefire-plugin + + false + + + + + + diff --git a/core-tests/e2e-tests/spring-rest-redis/src/main/java/com/redis/SwaggerConfiguration.java b/core-tests/e2e-tests/spring-rest-redis/src/main/java/com/redis/SwaggerConfiguration.java new file mode 100644 index 0000000000..f36a36c4db --- /dev/null +++ b/core-tests/e2e-tests/spring-rest-redis/src/main/java/com/redis/SwaggerConfiguration.java @@ -0,0 +1,38 @@ +package com.redis; + +import org.springframework.context.annotation.Bean; +import org.springframework.security.core.Authentication; +import org.springframework.web.context.request.WebRequest; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; + +import static springfox.documentation.builders.PathSelectors.regex; + +public class SwaggerConfiguration { + + String path; + + public SwaggerConfiguration(String path) { + this.path = path; + } + + @Bean + public Docket docketApi() { + return new Docket(DocumentationType.SWAGGER_2) + .apiInfo(apiInfo()) + .select() + .paths(regex("/" + path + "/.*")) + .build() + .ignoredParameterTypes(WebRequest.class, Authentication.class); + } + + private ApiInfo apiInfo() { + return new ApiInfoBuilder() + .title("API") + .description("Some description") + .version("1.0") + .build(); + } +} diff --git a/core-tests/e2e-tests/spring-rest-redis/src/main/java/com/redis/lettuce/RedisLettuceApp.java b/core-tests/e2e-tests/spring-rest-redis/src/main/java/com/redis/lettuce/RedisLettuceApp.java new file mode 100644 index 0000000000..428beea34b --- /dev/null +++ b/core-tests/e2e-tests/spring-rest-redis/src/main/java/com/redis/lettuce/RedisLettuceApp.java @@ -0,0 +1,20 @@ +package com.redis.lettuce; + +import com.redis.SwaggerConfiguration; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@EnableSwagger2 +@SpringBootApplication(exclude = SecurityAutoConfiguration.class) +public class RedisLettuceApp extends SwaggerConfiguration { + public RedisLettuceApp() { + super("redislettuce"); + } + + public static void main(String[] args) { + SpringApplication.run(RedisLettuceApp.class, args); + } + +} diff --git a/core-tests/e2e-tests/spring-rest-redis/src/main/java/com/redis/lettuce/RedisLettuceController.java b/core-tests/e2e-tests/spring-rest-redis/src/main/java/com/redis/lettuce/RedisLettuceController.java new file mode 100644 index 0000000000..a43bf2df43 --- /dev/null +++ b/core-tests/e2e-tests/spring-rest-redis/src/main/java/com/redis/lettuce/RedisLettuceController.java @@ -0,0 +1,54 @@ +package com.redis.lettuce; + +import io.lettuce.core.api.sync.RedisCommands; +import io.lettuce.core.api.StatefulRedisConnection; +import io.lettuce.core.RedisClient; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +@RestController +@RequestMapping(path = "/redislettuce") +public class RedisLettuceController { + + private RedisClient redisClient; + private StatefulRedisConnection connection; + private RedisCommands sync; + + @PostConstruct + public void init() { + String redisHost = System.getProperty("spring.redis.host", "localhost"); + String redisPort = System.getProperty("spring.redis.port", "6379"); + String redisUri = "redis://" + redisHost + ":" + redisPort; + redisClient = RedisClient.create(redisUri); + connection = redisClient.connect(); + sync = connection.sync(); + } + + @PreDestroy + public void shutdown() { + connection.close(); + redisClient.shutdown(); + } + + @PostMapping("/string/{key}") + public ResponseEntity saveData(@PathVariable String key) { + System.out.println("POST /string/"+ key); + sync.set(key, "value"); + return ResponseEntity.status(200).build(); + } + + @GetMapping("/findKey/{key}") + public ResponseEntity findKey(@PathVariable String key) { + String result = sync.get(key); + if (result != null) { + return ResponseEntity.status(200).build(); + } else { + return ResponseEntity.status(404).build(); + } + } +} + + diff --git a/core-tests/e2e-tests/spring-rest-redis/src/test/java/com/foo/spring/rest/redis/RedisController.java b/core-tests/e2e-tests/spring-rest-redis/src/test/java/com/foo/spring/rest/redis/RedisController.java new file mode 100644 index 0000000000..f3dfaec53a --- /dev/null +++ b/core-tests/e2e-tests/spring-rest-redis/src/test/java/com/foo/spring/rest/redis/RedisController.java @@ -0,0 +1,119 @@ +package com.foo.spring.rest.redis; + +import org.evomaster.client.java.controller.EmbeddedSutController; +import org.evomaster.client.java.controller.api.dto.auth.AuthenticationDto; +import org.evomaster.client.java.controller.api.dto.SutInfoDto; +import org.evomaster.client.java.controller.redis.RedisClient; +import org.evomaster.client.java.sql.DbSpecification; +import org.evomaster.client.java.controller.problem.ProblemInfo; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.testcontainers.containers.GenericContainer; +import org.evomaster.client.java.controller.problem.RestProblem; +import redis.clients.jedis.Jedis; + +import java.util.List; +import java.util.Map; + +public abstract class RedisController extends EmbeddedSutController { + + private static final int REDIS_DB_PORT = 6379; + private Jedis redisClient; + + private final GenericContainer redisContainer = new GenericContainer<>("redis:7.0") + .withExposedPorts(REDIS_DB_PORT); + private ConfigurableApplicationContext ctx; + + private final String databaseName; + + private final Class redisAppClass; + + private String host; + private int port; + + protected RedisController(String databaseName, Class redisAppClass) { + this.databaseName = databaseName; + this.redisAppClass = redisAppClass; + super.setControllerPort(0); + } + + @Override + public String startSut() { + redisContainer.start(); + + String host = redisContainer.getHost(); + int port = redisContainer.getMappedPort(REDIS_DB_PORT); + + System.setProperty("spring.redis.host", host); + System.setProperty("spring.redis.port", String.valueOf(port)); + this.host = host; + this.port = port; + + redisClient = new Jedis(host, port); + + SpringApplicationBuilder app = new SpringApplicationBuilder(redisAppClass); + + app.properties( + "--server.port=0", + "spring.data.redis.host=" + host, + "spring.data.redis.port=" + port + ); + + ctx = app.run(); + resetStateOfSUT(); + + return "http://localhost:" + getSutPort(); + } + + @Override + public void stopSut() { + redisContainer.stop(); + ctx.stop(); + ctx.close(); + } + + @Override + public void resetStateOfSUT() { + redisClient.flushDB(); + } + + @Override + public List getDbSpecifications() { + return null; + } + + @Override + public boolean isSutRunning() { + return ctx != null && ctx.isRunning(); + } + + @Override + public List getInfoForAuthentication() { + return null; + } + + @Override + public ProblemInfo getProblemInfo() { + return new RestProblem( + "http://localhost:" + getSutPort() + "/v2/api-docs", + null + ); + } + + @Override + public SutInfoDto.OutputFormat getPreferredOutputFormat() { + return null; + } + + protected int getSutPort() { + return (Integer) ((Map) ctx.getEnvironment() + .getPropertySources().get("server.ports").getSource()) + .get("local.server.port"); + } + + @Override + public RedisClient getRedisConnection() { + return new RedisClient(this.host, this.port); + } +} diff --git a/core-tests/e2e-tests/spring-rest-redis/src/test/java/com/foo/spring/rest/redis/lettuce/RedisLettuceAppController.java b/core-tests/e2e-tests/spring-rest-redis/src/test/java/com/foo/spring/rest/redis/lettuce/RedisLettuceAppController.java new file mode 100644 index 0000000000..4e9134ce4f --- /dev/null +++ b/core-tests/e2e-tests/spring-rest-redis/src/test/java/com/foo/spring/rest/redis/lettuce/RedisLettuceAppController.java @@ -0,0 +1,15 @@ +package com.foo.spring.rest.redis.lettuce; + +import com.foo.spring.rest.redis.RedisController; +import com.redis.lettuce.RedisLettuceApp; + +public class RedisLettuceAppController extends RedisController { + public RedisLettuceAppController() { + super("lettuce", RedisLettuceApp.class); + } + + @Override + public String getPackagePrefixesToCover() { + return "com.redis.lettuce"; + } +} diff --git a/core-tests/e2e-tests/spring-rest-redis/src/test/java/org/evomaster/e2etests/spring/rest/redis/RedisControllerTest.java b/core-tests/e2e-tests/spring-rest-redis/src/test/java/org/evomaster/e2etests/spring/rest/redis/RedisControllerTest.java new file mode 100644 index 0000000000..78dd8a04cb --- /dev/null +++ b/core-tests/e2e-tests/spring-rest-redis/src/test/java/org/evomaster/e2etests/spring/rest/redis/RedisControllerTest.java @@ -0,0 +1,15 @@ +package org.evomaster.e2etests.spring.rest.redis; + +import com.foo.spring.rest.redis.RedisController; +import com.foo.spring.rest.redis.lettuce.RedisLettuceAppController; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class RedisControllerTest { + @Test + public void testCanStartSut() { + RedisController controller = new RedisLettuceAppController(); + controller.startSut(); + assertTrue(controller.isSutRunning()); + } +} diff --git a/core-tests/e2e-tests/spring-rest-redis/src/test/java/org/evomaster/e2etests/spring/rest/redis/lettuce/RedisLettuceEMTest.java b/core-tests/e2e-tests/spring-rest-redis/src/test/java/org/evomaster/e2etests/spring/rest/redis/lettuce/RedisLettuceEMTest.java new file mode 100644 index 0000000000..257467fd75 --- /dev/null +++ b/core-tests/e2e-tests/spring-rest-redis/src/test/java/org/evomaster/e2etests/spring/rest/redis/lettuce/RedisLettuceEMTest.java @@ -0,0 +1,46 @@ +package org.evomaster.e2etests.spring.rest.redis.lettuce; + +import com.foo.spring.rest.redis.lettuce.RedisLettuceAppController; +import org.evomaster.core.EMConfig; +import org.evomaster.core.problem.rest.data.HttpVerb; +import org.evomaster.core.problem.rest.data.RestIndividual; +import org.evomaster.core.search.Solution; +import org.evomaster.e2etests.utils.RestTestBase; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class RedisLettuceEMTest extends RestTestBase { + + @BeforeAll + public static void initClass() throws Exception { + + EMConfig config = new EMConfig(); + config.setInstrumentMR_REDIS(true); + RestTestBase.initClass(new RedisLettuceAppController(), config); + } + + @Test + public void testRunEM() throws Throwable { + + runTestHandlingFlakyAndCompilation( + "RedisLettuceEM", + "org.foo.spring.rest.redis.RedisLettuceEM", + 1000, + true, + (args) -> { + setOption(args, "heuristicsForRedis", "true"); + setOption(args, "instrumentMR_REDIS", "true"); + + Solution solution = initAndRun(args); + + assertFalse(solution.getIndividuals().isEmpty()); + assertHasAtLeastOne(solution, HttpVerb.POST, 200, "/redislettuce/string/{key}", null); + assertHasAtLeastOne(solution, HttpVerb.GET, 200, "/redislettuce/findKey/{key}", null); + assertHasAtLeastOne(solution, HttpVerb.GET, 404, "/redislettuce/findKey/{key}", null); + }, + 3); + + } +} diff --git a/core/src/main/kotlin/org/evomaster/core/EMConfig.kt b/core/src/main/kotlin/org/evomaster/core/EMConfig.kt index 03d11140e3..a1747046a5 100644 --- a/core/src/main/kotlin/org/evomaster/core/EMConfig.kt +++ b/core/src/main/kotlin/org/evomaster/core/EMConfig.kt @@ -1621,6 +1621,10 @@ class EMConfig { @Cfg("Tracking of Mongo commands to improve test generation") var heuristicsForMongo = true + @Experimental + @Cfg("Tracking of Redis commands to improve test generation") + var heuristicsForRedis = false + @Cfg("Enable extracting SQL execution info") var extractSqlExecutionInfo = true @@ -1782,6 +1786,12 @@ class EMConfig { @Experimental var instrumentMR_OPENSEARCH = false + @Cfg("Execute instrumentation for method replace with category REDIS." + + " Note: this applies only for languages in which instrumentation is applied at runtime, like Java/Kotlin" + + " on the JVM.") + @Experimental + var instrumentMR_REDIS = false + @Cfg("Enable to expand the genotype of REST individuals based on runtime information missing from Swagger") var expandRestIndividuals = true @@ -2879,6 +2889,7 @@ class EMConfig { if (instrumentMR_NET) categories.add(ReplacementCategory.NET.toString()) if (instrumentMR_MONGO) categories.add(ReplacementCategory.MONGO.toString()) if (instrumentMR_OPENSEARCH) categories.add(ReplacementCategory.OPENSEARCH.toString()) + if (instrumentMR_REDIS) categories.add(ReplacementCategory.REDIS.toString()) return categories.joinToString(",") } diff --git a/core/src/main/kotlin/org/evomaster/core/problem/enterprise/service/EnterpriseFitness.kt b/core/src/main/kotlin/org/evomaster/core/problem/enterprise/service/EnterpriseFitness.kt index fdd590ce24..f66950d1bd 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/enterprise/service/EnterpriseFitness.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/enterprise/service/EnterpriseFitness.kt @@ -16,7 +16,6 @@ import org.evomaster.core.search.action.Action import org.evomaster.core.search.action.ActionResult import org.evomaster.core.search.FitnessValue import org.evomaster.core.search.Individual -import org.evomaster.core.search.TargetInfo import org.evomaster.core.search.gene.sql.SqlAutoIncrementGene import org.evomaster.core.search.gene.sql.SqlForeignKeyGene import org.evomaster.core.search.gene.sql.SqlPrimaryKeyGene @@ -330,6 +329,10 @@ abstract class EnterpriseFitness : FitnessFunction() where T : Individual } fv.aggregateMongoDatabaseData() } + + if (configuration.heuristicsForRedis) { + handleRedisHeuristics(dto, fv) + } } private fun handleSqlHeuristics( @@ -405,4 +408,37 @@ abstract class EnterpriseFitness : FitnessFunction() where T : Individual } } } + + private fun handleRedisHeuristics(dto: TestResultsDto, fv: FitnessValue) { + for (i in 0 until dto.extraHeuristics.size) { + + val extra = dto.extraHeuristics[i] + + extraHeuristicsLogger.writeHeuristics(extra.heuristics, i) + + val toMinimize = extra.heuristics + .filter { + it != null + && it.objective == ExtraHeuristicEntryDto.Objective.MINIMIZE_TO_ZERO + && it.type == ExtraHeuristicEntryDto.Type.REDIS + }.map { it.value } + .toList() + + if (toMinimize.isNotEmpty()) { + fv.setExtraToMinimize(i, toMinimize) + } + + extra.heuristics + .filterNotNull().forEach { + if (it.type == ExtraHeuristicEntryDto.Type.REDIS) { + statistics.reportNumberOfEvaluatedDocumentsForRedisHeuristic(it.numberOfEvaluatedRecords) + if (it.extraHeuristicEvaluationFailure) { + statistics.reportRedisHeuristicEvaluationFailure() + } else { + statistics.reportRedisHeuristicEvaluationSuccess() + } + } + } + } + } } diff --git a/core/src/main/kotlin/org/evomaster/core/search/service/Statistics.kt b/core/src/main/kotlin/org/evomaster/core/search/service/Statistics.kt index 724c84fab6..269b449f75 100644 --- a/core/src/main/kotlin/org/evomaster/core/search/service/Statistics.kt +++ b/core/src/main/kotlin/org/evomaster/core/search/service/Statistics.kt @@ -82,6 +82,11 @@ class Statistics : SearchListener { private var mongoHeuristicEvaluationFailureCount = 0 private val mongoDocumentsAverageCalculator = IncrementalAverage() + // redis heuristic evaluation statistic + private var redisHeuristicEvaluationSuccessCount = 0 + private var redisHeuristicEvaluationFailureCount = 0 + private val redisDocumentsAverageCalculator = IncrementalAverage() + class Pair(val header: String, val element: String) @@ -168,6 +173,10 @@ class Statistics : SearchListener { mongoDocumentsAverageCalculator.addValue(numberOfEvaluatedDocuments) } + fun reportNumberOfEvaluatedDocumentsForRedisHeuristic(numberOfEvaluatedDocuments: Int) { + redisDocumentsAverageCalculator.addValue(numberOfEvaluatedDocuments) + } + fun reportSqlParsingFailures(numberOfParsingFailures: Int) { if (numberOfParsingFailures<0) { throw IllegalArgumentException("Invalid number of parsing failures: $numberOfParsingFailures") @@ -191,6 +200,14 @@ class Statistics : SearchListener { mongoHeuristicEvaluationFailureCount++ } + fun reportRedisHeuristicEvaluationSuccess() { + redisHeuristicEvaluationSuccessCount++ + } + + fun reportRedisHeuristicEvaluationFailure() { + redisHeuristicEvaluationFailureCount++ + } + fun getMongoHeuristicsEvaluationCount(): Int = mongoHeuristicEvaluationSuccessCount + mongoHeuristicEvaluationFailureCount fun getSqlHeuristicsEvaluationCount(): Int = sqlHeuristicEvaluationSuccessCount + sqlHeuristicEvaluationFailureCount @@ -199,6 +216,10 @@ class Statistics : SearchListener { fun averageNumberOfEvaluatedDocumentsForMongoHeuristics(): Double = mongoDocumentsAverageCalculator.mean + fun getRedisHeuristicsEvaluationCount(): Int = redisHeuristicEvaluationSuccessCount + redisHeuristicEvaluationFailureCount + + fun averageNumberOfEvaluatedDocumentsForRedisHeuristics(): Double = redisDocumentsAverageCalculator.mean + override fun newActionEvaluated() { if (snapshotThreshold <= 0) { //not collecting snapshot data From af9f142775735e44bfbd1f1fdc8a546f13d2f4da Mon Sep 17 00:00:00 2001 From: Alexander Szyrej Date: Mon, 15 Dec 2025 04:09:08 -0300 Subject: [PATCH 3/9] Refactor after pulling master changes --- .gitignore | 1 + core-tests/e2e-tests/spring/pom.xml | 1 + .../{ => spring}/spring-rest-redis/pom.xml | 16 +++------------- .../java/com/redis/SwaggerConfiguration.java | 0 .../java/com/redis/lettuce/RedisLettuceApp.java | 0 .../redis/lettuce/RedisLettuceController.java | 1 - .../foo/spring/rest/redis/RedisController.java | 0 .../redis/lettuce/RedisLettuceAppController.java | 0 .../spring/rest/redis/RedisControllerTest.java | 0 .../rest/redis/lettuce/RedisLettuceEMTest.java | 0 10 files changed, 5 insertions(+), 14 deletions(-) rename core-tests/e2e-tests/{ => spring}/spring-rest-redis/pom.xml (89%) rename core-tests/e2e-tests/{ => spring}/spring-rest-redis/src/main/java/com/redis/SwaggerConfiguration.java (100%) rename core-tests/e2e-tests/{ => spring}/spring-rest-redis/src/main/java/com/redis/lettuce/RedisLettuceApp.java (100%) rename core-tests/e2e-tests/{ => spring}/spring-rest-redis/src/main/java/com/redis/lettuce/RedisLettuceController.java (96%) rename core-tests/e2e-tests/{ => spring}/spring-rest-redis/src/test/java/com/foo/spring/rest/redis/RedisController.java (100%) rename core-tests/e2e-tests/{ => spring}/spring-rest-redis/src/test/java/com/foo/spring/rest/redis/lettuce/RedisLettuceAppController.java (100%) rename core-tests/e2e-tests/{ => spring}/spring-rest-redis/src/test/java/org/evomaster/e2etests/spring/rest/redis/RedisControllerTest.java (100%) rename core-tests/e2e-tests/{ => spring}/spring-rest-redis/src/test/java/org/evomaster/e2etests/spring/rest/redis/lettuce/RedisLettuceEMTest.java (100%) diff --git a/.gitignore b/.gitignore index 7161fe28e4..e16a577048 100644 --- a/.gitignore +++ b/.gitignore @@ -105,6 +105,7 @@ Migrations/ /core-tests/e2e-tests/spring/spring-web/target/ /core-tests/e2e-tests/spring/spring-rest-mongo/target/ /core-tests/e2e-tests/spring/spring-rest-opensearch/target/ +/core-tests/e2e-tests/spring/spring-rest-redis/target/ /core-tests/client-java/target/ /core-tests/client-java/dependencies/target/ /core-tests/client-java/sql-dto/target/ diff --git a/core-tests/e2e-tests/spring/pom.xml b/core-tests/e2e-tests/spring/pom.xml index 52e4d07ef3..07c4fe9566 100644 --- a/core-tests/e2e-tests/spring/pom.xml +++ b/core-tests/e2e-tests/spring/pom.xml @@ -28,6 +28,7 @@ spring-graphql-bb spring-rest-multidb spring-rest-opensearch + spring-rest-redis spring-rest-rsa spring-rpc-grpc spring-rpc-thrift diff --git a/core-tests/e2e-tests/spring-rest-redis/pom.xml b/core-tests/e2e-tests/spring/spring-rest-redis/pom.xml similarity index 89% rename from core-tests/e2e-tests/spring-rest-redis/pom.xml rename to core-tests/e2e-tests/spring/spring-rest-redis/pom.xml index bd74c3af06..02362ec380 100644 --- a/core-tests/e2e-tests/spring-rest-redis/pom.xml +++ b/core-tests/e2e-tests/spring/spring-rest-redis/pom.xml @@ -4,7 +4,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - evomaster-e2e-tests + evomaster-e2e-tests-spring org.evomaster 4.0.1-SNAPSHOT @@ -51,10 +51,6 @@ validation-api 2.0.1.Final - - org.testcontainers - testcontainers - org.springframework.boot spring-boot-starter-data-redis @@ -64,12 +60,6 @@ jedis 5.1.0 - - org.testcontainers - junit-jupiter - 1.17.6 - test - io.springfox springfox-swagger2 @@ -90,7 +80,6 @@ - @@ -111,4 +100,5 @@ - + + \ No newline at end of file diff --git a/core-tests/e2e-tests/spring-rest-redis/src/main/java/com/redis/SwaggerConfiguration.java b/core-tests/e2e-tests/spring/spring-rest-redis/src/main/java/com/redis/SwaggerConfiguration.java similarity index 100% rename from core-tests/e2e-tests/spring-rest-redis/src/main/java/com/redis/SwaggerConfiguration.java rename to core-tests/e2e-tests/spring/spring-rest-redis/src/main/java/com/redis/SwaggerConfiguration.java diff --git a/core-tests/e2e-tests/spring-rest-redis/src/main/java/com/redis/lettuce/RedisLettuceApp.java b/core-tests/e2e-tests/spring/spring-rest-redis/src/main/java/com/redis/lettuce/RedisLettuceApp.java similarity index 100% rename from core-tests/e2e-tests/spring-rest-redis/src/main/java/com/redis/lettuce/RedisLettuceApp.java rename to core-tests/e2e-tests/spring/spring-rest-redis/src/main/java/com/redis/lettuce/RedisLettuceApp.java diff --git a/core-tests/e2e-tests/spring-rest-redis/src/main/java/com/redis/lettuce/RedisLettuceController.java b/core-tests/e2e-tests/spring/spring-rest-redis/src/main/java/com/redis/lettuce/RedisLettuceController.java similarity index 96% rename from core-tests/e2e-tests/spring-rest-redis/src/main/java/com/redis/lettuce/RedisLettuceController.java rename to core-tests/e2e-tests/spring/spring-rest-redis/src/main/java/com/redis/lettuce/RedisLettuceController.java index a43bf2df43..cf7756fad8 100644 --- a/core-tests/e2e-tests/spring-rest-redis/src/main/java/com/redis/lettuce/RedisLettuceController.java +++ b/core-tests/e2e-tests/spring/spring-rest-redis/src/main/java/com/redis/lettuce/RedisLettuceController.java @@ -35,7 +35,6 @@ public void shutdown() { @PostMapping("/string/{key}") public ResponseEntity saveData(@PathVariable String key) { - System.out.println("POST /string/"+ key); sync.set(key, "value"); return ResponseEntity.status(200).build(); } diff --git a/core-tests/e2e-tests/spring-rest-redis/src/test/java/com/foo/spring/rest/redis/RedisController.java b/core-tests/e2e-tests/spring/spring-rest-redis/src/test/java/com/foo/spring/rest/redis/RedisController.java similarity index 100% rename from core-tests/e2e-tests/spring-rest-redis/src/test/java/com/foo/spring/rest/redis/RedisController.java rename to core-tests/e2e-tests/spring/spring-rest-redis/src/test/java/com/foo/spring/rest/redis/RedisController.java diff --git a/core-tests/e2e-tests/spring-rest-redis/src/test/java/com/foo/spring/rest/redis/lettuce/RedisLettuceAppController.java b/core-tests/e2e-tests/spring/spring-rest-redis/src/test/java/com/foo/spring/rest/redis/lettuce/RedisLettuceAppController.java similarity index 100% rename from core-tests/e2e-tests/spring-rest-redis/src/test/java/com/foo/spring/rest/redis/lettuce/RedisLettuceAppController.java rename to core-tests/e2e-tests/spring/spring-rest-redis/src/test/java/com/foo/spring/rest/redis/lettuce/RedisLettuceAppController.java diff --git a/core-tests/e2e-tests/spring-rest-redis/src/test/java/org/evomaster/e2etests/spring/rest/redis/RedisControllerTest.java b/core-tests/e2e-tests/spring/spring-rest-redis/src/test/java/org/evomaster/e2etests/spring/rest/redis/RedisControllerTest.java similarity index 100% rename from core-tests/e2e-tests/spring-rest-redis/src/test/java/org/evomaster/e2etests/spring/rest/redis/RedisControllerTest.java rename to core-tests/e2e-tests/spring/spring-rest-redis/src/test/java/org/evomaster/e2etests/spring/rest/redis/RedisControllerTest.java diff --git a/core-tests/e2e-tests/spring-rest-redis/src/test/java/org/evomaster/e2etests/spring/rest/redis/lettuce/RedisLettuceEMTest.java b/core-tests/e2e-tests/spring/spring-rest-redis/src/test/java/org/evomaster/e2etests/spring/rest/redis/lettuce/RedisLettuceEMTest.java similarity index 100% rename from core-tests/e2e-tests/spring-rest-redis/src/test/java/org/evomaster/e2etests/spring/rest/redis/lettuce/RedisLettuceEMTest.java rename to core-tests/e2e-tests/spring/spring-rest-redis/src/test/java/org/evomaster/e2etests/spring/rest/redis/lettuce/RedisLettuceEMTest.java From 25aee6dd80472fae27efa054f9d2183730dc6859 Mon Sep 17 00:00:00 2001 From: Alexander Szyrej Date: Mon, 15 Dec 2025 20:31:30 -0300 Subject: [PATCH 4/9] Fixed options.md --- docs/options.md | 206 ++++++++++++++++++++++++------------------------ 1 file changed, 104 insertions(+), 102 deletions(-) diff --git a/docs/options.md b/docs/options.md index 9980693f46..b9d33b9a4f 100644 --- a/docs/options.md +++ b/docs/options.md @@ -1,34 +1,34 @@ # Command-Line Options -_EvoMaster_ has several options that can be configured. +_EvoMaster_ has several options that can be configured. Those can be set on the command-line when _EvoMaster_ is started. There are 3 types of options: * __Important__: those are the main options that most users will need to set - and know about. + and know about. * __Internal__: these are low-level tuning options, which most users do not need - to modify. These were mainly introduced when experimenting with - different configurations to maximize the performance of _EvoMaster_. - Some of these options are used to collect more info on the search, to help - debugging issues in _EvoMaster_ itself. - + to modify. These were mainly introduced when experimenting with + different configurations to maximize the performance of _EvoMaster_. + Some of these options are used to collect more info on the search, to help + debugging issues in _EvoMaster_ itself. + * __Experimental__: these are work-in-progress options, for features still under development - and testing. - + and testing. + + +The list of available options can also be displayed by using `--help`, e.g.: + +`java -jar evomaster.jar --help` - The list of available options can also be displayed by using `--help`, e.g.: +Options might also have *constraints*, e.g., a numeric value within a defined range, +or a string being an URL. +In some cases, strings might only be chosen within a specific set of possible values (i.e., an Enum). +If any constraint is not satisfied, _EvoMaster_ will fail with an error message. + +When used, all options need to be prefixed with a `--`, e.g., `--maxTime`. - `java -jar evomaster.jar --help` - - Options might also have *constraints*, e.g., a numeric value within a defined range, - or a string being an URL. - In some cases, strings might only be chosen within a specific set of possible values (i.e., an Enum). - If any constraint is not satisfied, _EvoMaster_ will fail with an error message. - - When used, all options need to be prefixed with a `--`, e.g., `--maxTime`. - ## Important Command-Line Options |Options|Description| @@ -241,86 +241,88 @@ There are 3 types of options: ## Experimental Command-Line Options -|Options|Description| -|---|---| -|`aIClassificationMetrics`| __Enum__. Determines which metric-tracking strategy is used by the AI response classifier. *Valid values*: `TIME_WINDOW, FULL_HISTORY`. *Default value*: `TIME_WINDOW`.| -|`abstractInitializationGeneToMutate`| __Boolean__. During mutation, whether to abstract genes for repeated SQL actions. *Default value*: `false`.| -|`aiClassifierRepairActivation`| __Enum__. Specify how the classification of actions's response will be used to execute a possible repair on the action. *Valid values*: `PROBABILITY, THRESHOLD`. *Default value*: `THRESHOLD`.| -|`aiEncoderType`| __Enum__. The encoding strategy applied to transform raw data to the encoded version. *Valid values*: `RAW, NORMAL, UNIT_NORMAL`. *Default value*: `RAW`.| -|`aiModelForResponseClassification`| __Enum__. Model used to learn input constraints and infer response status before making request. *Valid values*: `NONE, GAUSSIAN, KDE, KNN, NN, GLM, DETERMINISTIC`. *Default value*: `NONE`.| -|`aiResponseClassifierLearningRate`| __Double__. Learning rate controlling the step size during parameter updates in classifiers. Relevant for gradient-based models such as GLM and neural networks. A smaller value ensures stable but slower convergence, while a larger value speeds up training but may cause instability. *Default value*: `0.01`.| -|`aiResponseClassifierMaxStoredSamples`| __Int__. Maximum number of stored samples for classifiers such as KNN and KDE models that rely on retaining encoded inputs. This value specifies the maximum number of samples stored for each endpoint. A higher value can improve classification accuracy by leveraging more historical data, but also increases memory usage. A lower value reduces memory consumption but may limit the classifier’s knowledge base. Typically, it is safe to keep this value between 10,000 and 50,000 when the encoded input vector is usually a list of doubles with a length under 20. Reservoir sampling is applied independently for each endpoint: if this maximum number is exceeded, new samples randomly replace existing ones, ensuring an unbiased selection of preserved data. As an example, for an API with 100 endpoints and an input vector of size 20, a maximum of 10,000 samples per endpoint would require roughly 200 MB of memory. *Default value*: `10000`.| -|`aiResponseClassifierWarmup`| __Int__. Number of training iterations required to update classifier parameters. For example, in the Gaussian model this affects mean and variance updates. For neural network (NN) models, the warm-up should typically be larger than 1000. *Default value*: `10`.| -|`appendToTargetHeuristicsFile`| __Boolean__. Whether should add to an existing target heuristics file, instead of replacing it. It is only used when processFormat is TARGET_HEURISTIC. *Default value*: `false`.| -|`bbProbabilityUseDataPool`| __Double__. Specify the probability of using the data pool when sampling test cases. This is for black-box (bb) mode. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.8`.| -|`breederParentsMin`| __Int__. Breeder GA: minimum number of individuals in parents pool after truncation. *Constraints*: `min=2.0`. *Default value*: `2`.| -|`breederTruncationFraction`| __Double__. Breeder GA: fraction of top individuals to keep in parents pool (truncation). *Constraints*: `probability 0.0-1.0`. *Default value*: `0.5`.| -|`callbackURLHostname`| __String__. HTTP callback verifier hostname. Default is set to 'localhost'. If the SUT is running inside a container (i.e., Docker), 'localhost' will refer to the container. This can be used to change the hostname. *Default value*: `localhost`.| -|`cgaNeighborhoodModel`| __Enum__. Cellular GA: neighborhood model (RING, L5, C9, C13). *Valid values*: `RING, L5, C9, C13`. *Default value*: `RING`.| -|`classificationRepairThreshold`| __Double__. If using THRESHOLD for AI Classification Repair, specify its value. All classifications with probability equal or above such threshold value will be accepted. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.8`.| -|`discoveredInfoRewardedInFitness`| __Boolean__. If there is new discovered information from a test execution, reward it in the fitness function. *Default value*: `false`.| -|`dockerLocalhost`| __Boolean__. Replace references to 'localhost' to point to the actual host machine. Only needed when running EvoMaster inside Docker. *Default value*: `false`.| -|`dpcTargetTestSize`| __Int__. Specify a max size of a test to be targeted when either DPC_INCREASING or DPC_DECREASING is enabled. *Default value*: `1`.| -|`dtoForRequestPayload`| __Boolean__. In REST APIs, when request Content-Type is JSON, POJOs are used instead of raw JSON string. Only available for JVM languages. *Default value*: `false`.| -|`employResourceSizeHandlingStrategy`| __Enum__. Specify a strategy to determinate a number of resources to be manipulated throughout the search. *Valid values*: `NONE, RANDOM, DPC`. *Default value*: `NONE`.| -|`enableAdaptiveResourceStructureMutation`| __Boolean__. Specify whether to decide the resource-based structure mutator and resource to be mutated adaptively based on impacts during focused search.Note that it only works when resource-based solution is enabled for solving REST problem. *Default value*: `false`.| -|`enableCustomizedMethodForMockObjectHandling`| __Boolean__. Whether to apply customized method (i.e., implement 'customizeMockingRPCExternalService' for external services or 'customizeMockingDatabase' for database) to handle mock object. *Default value*: `false`.| -|`enableCustomizedMethodForScheduleTaskHandling`| __Boolean__. Whether to apply customized method (i.e., implement 'customizeScheduleTaskInvocation' for invoking schedule task) to invoke schedule task. *Default value*: `false`.| -|`enableRPCCustomizedTestOutput`| __Boolean__. Whether to enable customized RPC Test output if 'customizeRPCTestOutput' is implemented. *Default value*: `false`.| -|`enableWriteSnapshotTests`| __Boolean__. Enable to print snapshots of the generated tests during the search in an interval defined in snapshotsInterval. *Default value*: `false`.| -|`executiveSummary`| __Boolean__. Generate an executive summary, containing an example of each category of potential faults found.NOTE: This option is only meaningful when used in conjunction with test suite splitting. *Default value*: `false`.| -|`expectationsActive`| __Boolean__. Enable Expectation Generation. If enabled, expectations will be generated. A variable called expectationsMasterSwitch is added to the test suite, with a default value of false. If set to true, an expectation that fails will cause the test case containing it to fail. *Default value*: `false`.| -|`exportTestCasesDuringSeeding`| __Boolean__. Whether to export test cases during seeding as a separate file. *Default value*: `false`.| -|`externalRequestHarvesterNumberOfThreads`| __Int__. Number of threads for external request harvester. No more threads than numbers of processors will be used. *Constraints*: `min=1.0`. *Default value*: `2`.| -|`externalRequestResponseSelectionStrategy`| __Enum__. Harvested external request response selection strategy. *Valid values*: `EXACT, CLOSEST_SAME_DOMAIN, CLOSEST_SAME_PATH, RANDOM`. *Default value*: `EXACT`.| -|`externalServiceIP`| __String__. User provided external service IP. When EvoMaster mocks external services, mock server instances will run on local addresses starting from this provided address. Min value is 127.0.0.4. Lower values like 127.0.0.2 and 127.0.0.3 are reserved. *Constraints*: `regex (?!^0*127(\.0*0){2}\.0*[0123]$)^0*127(\.0*(25[0-5]\|2[0-4][0-9]\|1?[0-9]?[0-9])){3}$`. *Default value*: `127.0.0.4`.| -|`externalServiceIPSelectionStrategy`| __Enum__. Specify a method to select the first external service spoof IP address. *Valid values*: `NONE, DEFAULT, USER, RANDOM`. *Default value*: `NONE`.| -|`generateSqlDataWithDSE`| __Boolean__. Enable EvoMaster to generate SQL data with direct accesses to the database. Use Dynamic Symbolic Execution. *Default value*: `false`.| -|`heuristicsForSQLAdvanced`| __Boolean__. If using SQL heuristics, enable more advanced version. *Default value*: `false`.| -|`httpOracles`| __Boolean__. Extra checks on HTTP properties in returned responses, used as automated oracles to detect faults. *Default value*: `false`.| -|`initStructureMutationProbability`| __Double__. Probability of applying a mutation that can change the structure of test's initialization if it has. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`.| -|`instrumentMR_NET`| __Boolean__. Execute instrumentation for method replace with category NET. Note: this applies only for languages in which instrumentation is applied at runtime, like Java/Kotlin on the JVM. *Default value*: `false`.| -|`instrumentMR_OPENSEARCH`| __Boolean__. Execute instrumentation for method replace with category OPENSEARCH. Note: this applies only for languages in which instrumentation is applied at runtime, like Java/Kotlin on the JVM. *Default value*: `false`.| -|`languageModelConnector`| __Boolean__. Enable language model connector. *Default value*: `false`.| -|`languageModelConnectorNumberOfThreads`| __Int__. Number of threads for language model connector. No more threads than numbers of processors will be used. *Constraints*: `min=1.0`. *Default value*: `2`.| -|`languageModelName`| __String__. Large-language model name as listed in Ollama. *Default value*: `llama3.2:latest`.| -|`languageModelServerURL`| __String__. Large-language model external service URL. Default is set to Ollama local instance URL. *Default value*: `http://localhost:11434/`.| -|`maxRepairAttemptsInResponseClassification`| __Int__. When the Response Classifier determines an action is going to fail, specify how many attempts will be tried at fixing it. *Constraints*: `min=1.0`. *Default value*: `100`.| -|`maxResourceSize`| __Int__. Specify a max size of resources in a test. 0 means the there is no specified restriction on a number of resources. *Constraints*: `min=0.0`. *Default value*: `0`.| -|`maxSizeDataPool`| __Int__. How much data elements, per key, can be stored in the Data Pool. Once limit is reached, new old will replace old data. *Constraints*: `min=1.0`. *Default value*: `100`.| -|`maxSizeOfExistingDataToSample`| __Int__. Specify a maximum number of existing data in the database to sample in a test when SQL handling is enabled. Note that a negative number means all existing data would be sampled. *Default value*: `-1`.| -|`maxSizeOfHandlingResource`| __Int__. Specify a maximum number of handling (remove/add) resource size at once, e.g., add 3 resource at most. *Constraints*: `min=0.0`. *Default value*: `0`.| -|`maxSizeOfMutatingInitAction`| __Int__. Specify a maximum number of handling (remove/add) init actions at once, e.g., add 3 init actions at most. *Constraints*: `min=0.0`. *Default value*: `0`.| -|`maxTestSizeStrategy`| __Enum__. Specify a strategy to handle a max size of a test. *Valid values*: `SPECIFIED, DPC_INCREASING, DPC_DECREASING`. *Default value*: `SPECIFIED`.| -|`maxTestsPerTestSuite`| __Int__. Specify the maximum number of tests to be generated in one test suite. Note that a negative number presents no limit per test suite. *Default value*: `-1`.| -|`mutationTargetsSelectionStrategy`| __Enum__. Specify a strategy to select targets for evaluating mutation. *Valid values*: `FIRST_NOT_COVERED_TARGET, EXPANDED_UPDATED_NOT_COVERED_TARGET, UPDATED_NOT_COVERED_TARGET`. *Default value*: `FIRST_NOT_COVERED_TARGET`.| -|`onePlusLambdaLambdaOffspringSize`| __Int__. 1+(λ,λ) GA: number of offspring (λ) per generation. *Constraints*: `min=1.0`. *Default value*: `4`.| -|`prematureStopStrategy`| __Enum__. Specify how 'improvement' is defined: either any kind of improvement even if partial (ANY), or at least one new target is fully covered (NEW). *Valid values*: `ANY, NEW`. *Default value*: `NEW`.| -|`probOfHandlingLength`| __Double__. Specify a probability of applying length handling. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`.| -|`probOfHarvestingResponsesFromActualExternalServices`| __Double__. a probability of harvesting actual responses from external services as seeds. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`.| -|`probOfMutatingResponsesBasedOnActualResponse`| __Double__. a probability of mutating mocked responses based on actual responses. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`.| -|`probOfPrioritizingSuccessfulHarvestedActualResponses`| __Double__. a probability of prioritizing to employ successful harvested actual responses from external services as seeds (e.g., 2xx from HTTP external service). *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`.| -|`probOfSamplingScheduleTask`| __Double__. Probability of sampling a new individual with schedule tasks. Note that schedule task is only enabled for RPCProblem. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`.| -|`probOfSmartInitStructureMutator`| __Double__. Specify a probability of applying a smart structure mutator for initialization of the individual. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`.| -|`probabilityAllOptionalsAreOnOrOff`| __Double__. When sampling a new individual, probability that ALL optional choices are ON, or ALL are OFF. The choice between ON and OFF depends on probabilityOfOnVsOffInAllOptionals. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`.| -|`saveMockedResponseAsSeparatedFile`| __Boolean__. Whether to save mocked responses as separated files. *Default value*: `false`.| -|`saveScheduleTaskInvocationAsSeparatedFile`| __Boolean__. Whether to save schedule task invocation as separated files. *Default value*: `false`.| -|`saveTargetHeuristicsPrefixes`| __String__. Prefix specifying which targets to record. Each target can be separated by a comma, such as 'Branch,Line,Success, etc'. It is only used when processFormat is TARGET_HEURISTIC. *Default value*: `Branch`.| -|`seedTestCases`| __Boolean__. Whether to seed EvoMaster with some initial test cases. These test cases will be used and evolved throughout the search process. *Default value*: `false`.| -|`seedTestCasesFormat`| __Enum__. Format of the test cases seeded to EvoMaster. *Valid values*: `POSTMAN`. *Default value*: `POSTMAN`.| -|`seedTestCasesPath`| __String__. File path where the seeded test cases are located. *Default value*: `postman.postman_collection.json`.| -|`ssrf`| __Boolean__. To apply SSRF detection as part of security testing. *Default value*: `false`.| -|`structureMutationProFS`| __Double__. Specify a probability of applying structure mutator during the focused search. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`.| -|`structureMutationProbStrategy`| __Enum__. Specify a strategy to handle a probability of applying structure mutator during the focused search. *Valid values*: `SPECIFIED, SPECIFIED_FS, DPC_TO_SPECIFIED_BEFORE_FS, DPC_TO_SPECIFIED_AFTER_FS, ADAPTIVE_WITH_IMPACT`. *Default value*: `SPECIFIED`.| -|`taintForceSelectionOfGenesWithSpecialization`| __Boolean__. During mutation, force the mutation of genes that have newly discovered specialization from previous fitness evaluations, based on taint analysis. *Default value*: `false`.| -|`targetHeuristicsFile`| __String__. Where the target heuristic values file (if any) is going to be written (in CSV format). It is only used when processFormat is TARGET_HEURISTIC. *Default value*: `targets.csv`.| -|`testResourcePathToSaveMockedResponse`| __String__. Specify test resource path where to save mocked responses as separated files. *Default value*: `""`.| -|`thresholdDistanceForDataPool`| __Int__. Threshold of Levenshtein Distance for key-matching in Data Pool. *Constraints*: `min=0.0`. *Default value*: `2`.| -|`useGlobalTaintInfoProbability`| __Double__. When sampling new individual, check whether to use already existing info on tainted values. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`.| -|`useInsertionForSqlHeuristics`| __Boolean__. Specify whether insertions should be used to calculate SQL heuristics instead of retrieving data from real databases. *Default value*: `false`.| -|`useTestMethodOrder`| __Boolean__. Adds TestMethodOrder annotation for JUnit 5 tests. *Default value*: `false`.| -|`useWeightedSampling`| __Boolean__. When sampling from archive based on targets, decide whether to use weights based on properties of the targets (e.g., a target likely leading to a flag will be sampled less often). *Default value*: `false`.| -|`vulnerableInputClassificationStrategy`| __Enum__. Strategy to classify inputs for potential vulnerability classes related to an REST endpoint. *Valid values*: `MANUAL, LLM`. *Default value*: `MANUAL`.| -|`wbProbabilityUseDataPool`| __Double__. Specify the probability of using the data pool when sampling test cases. This is for white-box (wb) mode. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.2`.| -|`writeSnapshotTestsIntervalInSeconds`| __Int__. The size (in seconds) of the interval that the snapshots will be printed, if enabled. *Default value*: `3600`.| -|`xss`| __Boolean__. To apply XSS detection as part of security testing. *Default value*: `false`.| +| Options | Description | +|--------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `aIClassificationMetrics` | __Enum__. Determines which metric-tracking strategy is used by the AI response classifier. *Valid values*: `TIME_WINDOW, FULL_HISTORY`. *Default value*: `TIME_WINDOW`. | +| `abstractInitializationGeneToMutate` | __Boolean__. During mutation, whether to abstract genes for repeated SQL actions. *Default value*: `false`. | +| `aiClassifierRepairActivation` | __Enum__. Specify how the classification of actions's response will be used to execute a possible repair on the action. *Valid values*: `PROBABILITY, THRESHOLD`. *Default value*: `THRESHOLD`. | +| `aiEncoderType` | __Enum__. The encoding strategy applied to transform raw data to the encoded version. *Valid values*: `RAW, NORMAL, UNIT_NORMAL`. *Default value*: `RAW`. | +| `aiModelForResponseClassification` | __Enum__. Model used to learn input constraints and infer response status before making request. *Valid values*: `NONE, GAUSSIAN, KDE, KNN, NN, GLM, DETERMINISTIC`. *Default value*: `NONE`. | +| `aiResponseClassifierLearningRate` | __Double__. Learning rate controlling the step size during parameter updates in classifiers. Relevant for gradient-based models such as GLM and neural networks. A smaller value ensures stable but slower convergence, while a larger value speeds up training but may cause instability. *Default value*: `0.01`. | +| `aiResponseClassifierMaxStoredSamples` | __Int__. Maximum number of stored samples for classifiers such as KNN and KDE models that rely on retaining encoded inputs. This value specifies the maximum number of samples stored for each endpoint. A higher value can improve classification accuracy by leveraging more historical data, but also increases memory usage. A lower value reduces memory consumption but may limit the classifier’s knowledge base. Typically, it is safe to keep this value between 10,000 and 50,000 when the encoded input vector is usually a list of doubles with a length under 20. Reservoir sampling is applied independently for each endpoint: if this maximum number is exceeded, new samples randomly replace existing ones, ensuring an unbiased selection of preserved data. As an example, for an API with 100 endpoints and an input vector of size 20, a maximum of 10,000 samples per endpoint would require roughly 200 MB of memory. *Default value*: `10000`. | +| `aiResponseClassifierWarmup` | __Int__. Number of training iterations required to update classifier parameters. For example, in the Gaussian model this affects mean and variance updates. For neural network (NN) models, the warm-up should typically be larger than 1000. *Default value*: `10`. | +| `appendToTargetHeuristicsFile` | __Boolean__. Whether should add to an existing target heuristics file, instead of replacing it. It is only used when processFormat is TARGET_HEURISTIC. *Default value*: `false`. | +| `bbProbabilityUseDataPool` | __Double__. Specify the probability of using the data pool when sampling test cases. This is for black-box (bb) mode. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.8`. | +| `breederParentsMin` | __Int__. Breeder GA: minimum number of individuals in parents pool after truncation. *Constraints*: `min=2.0`. *Default value*: `2`. | +| `breederTruncationFraction` | __Double__. Breeder GA: fraction of top individuals to keep in parents pool (truncation). *Constraints*: `probability 0.0-1.0`. *Default value*: `0.5`. | +| `callbackURLHostname` | __String__. HTTP callback verifier hostname. Default is set to 'localhost'. If the SUT is running inside a container (i.e., Docker), 'localhost' will refer to the container. This can be used to change the hostname. *Default value*: `localhost`. | +| `cgaNeighborhoodModel` | __Enum__. Cellular GA: neighborhood model (RING, L5, C9, C13). *Valid values*: `RING, L5, C9, C13`. *Default value*: `RING`. | +| `classificationRepairThreshold` | __Double__. If using THRESHOLD for AI Classification Repair, specify its value. All classifications with probability equal or above such threshold value will be accepted. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.8`. | +| `discoveredInfoRewardedInFitness` | __Boolean__. If there is new discovered information from a test execution, reward it in the fitness function. *Default value*: `false`. | +| `dockerLocalhost` | __Boolean__. Replace references to 'localhost' to point to the actual host machine. Only needed when running EvoMaster inside Docker. *Default value*: `false`. | +| `dpcTargetTestSize` | __Int__. Specify a max size of a test to be targeted when either DPC_INCREASING or DPC_DECREASING is enabled. *Default value*: `1`. | +| `dtoForRequestPayload` | __Boolean__. In REST APIs, when request Content-Type is JSON, POJOs are used instead of raw JSON string. Only available for JVM languages. *Default value*: `false`. | +| `employResourceSizeHandlingStrategy` | __Enum__. Specify a strategy to determinate a number of resources to be manipulated throughout the search. *Valid values*: `NONE, RANDOM, DPC`. *Default value*: `NONE`. | +| `enableAdaptiveResourceStructureMutation` | __Boolean__. Specify whether to decide the resource-based structure mutator and resource to be mutated adaptively based on impacts during focused search.Note that it only works when resource-based solution is enabled for solving REST problem. *Default value*: `false`. | +| `enableCustomizedMethodForMockObjectHandling` | __Boolean__. Whether to apply customized method (i.e., implement 'customizeMockingRPCExternalService' for external services or 'customizeMockingDatabase' for database) to handle mock object. *Default value*: `false`. | +| `enableCustomizedMethodForScheduleTaskHandling` | __Boolean__. Whether to apply customized method (i.e., implement 'customizeScheduleTaskInvocation' for invoking schedule task) to invoke schedule task. *Default value*: `false`. | +| `enableRPCCustomizedTestOutput` | __Boolean__. Whether to enable customized RPC Test output if 'customizeRPCTestOutput' is implemented. *Default value*: `false`. | +| `enableWriteSnapshotTests` | __Boolean__. Enable to print snapshots of the generated tests during the search in an interval defined in snapshotsInterval. *Default value*: `false`. | +| `executiveSummary` | __Boolean__. Generate an executive summary, containing an example of each category of potential faults found.NOTE: This option is only meaningful when used in conjunction with test suite splitting. *Default value*: `false`. | +| `expectationsActive` | __Boolean__. Enable Expectation Generation. If enabled, expectations will be generated. A variable called expectationsMasterSwitch is added to the test suite, with a default value of false. If set to true, an expectation that fails will cause the test case containing it to fail. *Default value*: `false`. | +| `exportTestCasesDuringSeeding` | __Boolean__. Whether to export test cases during seeding as a separate file. *Default value*: `false`. | +| `externalRequestHarvesterNumberOfThreads` | __Int__. Number of threads for external request harvester. No more threads than numbers of processors will be used. *Constraints*: `min=1.0`. *Default value*: `2`. | +| `externalRequestResponseSelectionStrategy` | __Enum__. Harvested external request response selection strategy. *Valid values*: `EXACT, CLOSEST_SAME_DOMAIN, CLOSEST_SAME_PATH, RANDOM`. *Default value*: `EXACT`. | +| `externalServiceIP` | __String__. User provided external service IP. When EvoMaster mocks external services, mock server instances will run on local addresses starting from this provided address. Min value is 127.0.0.4. Lower values like 127.0.0.2 and 127.0.0.3 are reserved. *Constraints*: `regex (?!^0*127(\.0*0){2}\.0*[0123]$)^0*127(\.0*(25[0-5]\|2[0-4][0-9]\|1?[0-9]?[0-9])){3}$`. *Default value*: `127.0.0.4`. | +| `externalServiceIPSelectionStrategy` | __Enum__. Specify a method to select the first external service spoof IP address. *Valid values*: `NONE, DEFAULT, USER, RANDOM`. *Default value*: `NONE`. | +| `generateSqlDataWithDSE` | __Boolean__. Enable EvoMaster to generate SQL data with direct accesses to the database. Use Dynamic Symbolic Execution. *Default value*: `false`. | +| `heuristicsForSQLAdvanced` | __Boolean__. If using SQL heuristics, enable more advanced version. *Default value*: `false`. | +| `heuristicsForRedis` | __Boolean__. Tracking of Redis commands to improve test generation. *Default value*: `false`. | +| `httpOracles` | __Boolean__. Extra checks on HTTP properties in returned responses, used as automated oracles to detect faults. *Default value*: `false`. | +| `initStructureMutationProbability` | __Double__. Probability of applying a mutation that can change the structure of test's initialization if it has. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`. | +| `instrumentMR_NET` | __Boolean__. Execute instrumentation for method replace with category NET. Note: this applies only for languages in which instrumentation is applied at runtime, like Java/Kotlin on the JVM. *Default value*: `false`. | +| `instrumentMR_OPENSEARCH` | __Boolean__. Execute instrumentation for method replace with category OPENSEARCH. Note: this applies only for languages in which instrumentation is applied at runtime, like Java/Kotlin on the JVM. *Default value*: `false`. | +| `instrumentMR_REDIS` | __Boolean__. Execute instrumentation for method replace with category REDIS. Note: this applies only for languages in which instrumentation is applied at runtime, like Java/Kotlin on the JVM. *Default value*: `false`. | +| `languageModelConnector` | __Boolean__. Enable language model connector. *Default value*: `false`. | +| `languageModelConnectorNumberOfThreads` | __Int__. Number of threads for language model connector. No more threads than numbers of processors will be used. *Constraints*: `min=1.0`. *Default value*: `2`. | +| `languageModelName` | __String__. Large-language model name as listed in Ollama. *Default value*: `llama3.2:latest`. | +| `languageModelServerURL` | __String__. Large-language model external service URL. Default is set to Ollama local instance URL. *Default value*: `http://localhost:11434/`. | +| `maxRepairAttemptsInResponseClassification` | __Int__. When the Response Classifier determines an action is going to fail, specify how many attempts will be tried at fixing it. *Constraints*: `min=1.0`. *Default value*: `100`. | +| `maxResourceSize` | __Int__. Specify a max size of resources in a test. 0 means the there is no specified restriction on a number of resources. *Constraints*: `min=0.0`. *Default value*: `0`. | +| `maxSizeDataPool` | __Int__. How much data elements, per key, can be stored in the Data Pool. Once limit is reached, new old will replace old data. *Constraints*: `min=1.0`. *Default value*: `100`. | +| `maxSizeOfExistingDataToSample` | __Int__. Specify a maximum number of existing data in the database to sample in a test when SQL handling is enabled. Note that a negative number means all existing data would be sampled. *Default value*: `-1`. | +| `maxSizeOfHandlingResource` | __Int__. Specify a maximum number of handling (remove/add) resource size at once, e.g., add 3 resource at most. *Constraints*: `min=0.0`. *Default value*: `0`. | +| `maxSizeOfMutatingInitAction` | __Int__. Specify a maximum number of handling (remove/add) init actions at once, e.g., add 3 init actions at most. *Constraints*: `min=0.0`. *Default value*: `0`. | +| `maxTestSizeStrategy` | __Enum__. Specify a strategy to handle a max size of a test. *Valid values*: `SPECIFIED, DPC_INCREASING, DPC_DECREASING`. *Default value*: `SPECIFIED`. | +| `maxTestsPerTestSuite` | __Int__. Specify the maximum number of tests to be generated in one test suite. Note that a negative number presents no limit per test suite. *Default value*: `-1`. | +| `mutationTargetsSelectionStrategy` | __Enum__. Specify a strategy to select targets for evaluating mutation. *Valid values*: `FIRST_NOT_COVERED_TARGET, EXPANDED_UPDATED_NOT_COVERED_TARGET, UPDATED_NOT_COVERED_TARGET`. *Default value*: `FIRST_NOT_COVERED_TARGET`. | +| `onePlusLambdaLambdaOffspringSize` | __Int__. 1+(λ,λ) GA: number of offspring (λ) per generation. *Constraints*: `min=1.0`. *Default value*: `4`. | +| `prematureStopStrategy` | __Enum__. Specify how 'improvement' is defined: either any kind of improvement even if partial (ANY), or at least one new target is fully covered (NEW). *Valid values*: `ANY, NEW`. *Default value*: `NEW`. | +| `probOfHandlingLength` | __Double__. Specify a probability of applying length handling. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`. | +| `probOfHarvestingResponsesFromActualExternalServices` | __Double__. a probability of harvesting actual responses from external services as seeds. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`. | +| `probOfMutatingResponsesBasedOnActualResponse` | __Double__. a probability of mutating mocked responses based on actual responses. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`. | +| `probOfPrioritizingSuccessfulHarvestedActualResponses` | __Double__. a probability of prioritizing to employ successful harvested actual responses from external services as seeds (e.g., 2xx from HTTP external service). *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`. | +| `probOfSamplingScheduleTask` | __Double__. Probability of sampling a new individual with schedule tasks. Note that schedule task is only enabled for RPCProblem. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`. | +| `probOfSmartInitStructureMutator` | __Double__. Specify a probability of applying a smart structure mutator for initialization of the individual. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`. | +| `probabilityAllOptionalsAreOnOrOff` | __Double__. When sampling a new individual, probability that ALL optional choices are ON, or ALL are OFF. The choice between ON and OFF depends on probabilityOfOnVsOffInAllOptionals. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`. | +| `saveMockedResponseAsSeparatedFile` | __Boolean__. Whether to save mocked responses as separated files. *Default value*: `false`. | +| `saveScheduleTaskInvocationAsSeparatedFile` | __Boolean__. Whether to save schedule task invocation as separated files. *Default value*: `false`. | +| `saveTargetHeuristicsPrefixes` | __String__. Prefix specifying which targets to record. Each target can be separated by a comma, such as 'Branch,Line,Success, etc'. It is only used when processFormat is TARGET_HEURISTIC. *Default value*: `Branch`. | +| `seedTestCases` | __Boolean__. Whether to seed EvoMaster with some initial test cases. These test cases will be used and evolved throughout the search process. *Default value*: `false`. | +| `seedTestCasesFormat` | __Enum__. Format of the test cases seeded to EvoMaster. *Valid values*: `POSTMAN`. *Default value*: `POSTMAN`. | +| `seedTestCasesPath` | __String__. File path where the seeded test cases are located. *Default value*: `postman.postman_collection.json`. | +| `ssrf` | __Boolean__. To apply SSRF detection as part of security testing. *Default value*: `false`. | +| `structureMutationProFS` | __Double__. Specify a probability of applying structure mutator during the focused search. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`. | +| `structureMutationProbStrategy` | __Enum__. Specify a strategy to handle a probability of applying structure mutator during the focused search. *Valid values*: `SPECIFIED, SPECIFIED_FS, DPC_TO_SPECIFIED_BEFORE_FS, DPC_TO_SPECIFIED_AFTER_FS, ADAPTIVE_WITH_IMPACT`. *Default value*: `SPECIFIED`. | +| `taintForceSelectionOfGenesWithSpecialization` | __Boolean__. During mutation, force the mutation of genes that have newly discovered specialization from previous fitness evaluations, based on taint analysis. *Default value*: `false`. | +| `targetHeuristicsFile` | __String__. Where the target heuristic values file (if any) is going to be written (in CSV format). It is only used when processFormat is TARGET_HEURISTIC. *Default value*: `targets.csv`. | +| `testResourcePathToSaveMockedResponse` | __String__. Specify test resource path where to save mocked responses as separated files. *Default value*: `""`. | +| `thresholdDistanceForDataPool` | __Int__. Threshold of Levenshtein Distance for key-matching in Data Pool. *Constraints*: `min=0.0`. *Default value*: `2`. | +| `useGlobalTaintInfoProbability` | __Double__. When sampling new individual, check whether to use already existing info on tainted values. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`. | +| `useInsertionForSqlHeuristics` | __Boolean__. Specify whether insertions should be used to calculate SQL heuristics instead of retrieving data from real databases. *Default value*: `false`. | +| `useTestMethodOrder` | __Boolean__. Adds TestMethodOrder annotation for JUnit 5 tests. *Default value*: `false`. | +| `useWeightedSampling` | __Boolean__. When sampling from archive based on targets, decide whether to use weights based on properties of the targets (e.g., a target likely leading to a flag will be sampled less often). *Default value*: `false`. | +| `vulnerableInputClassificationStrategy` | __Enum__. Strategy to classify inputs for potential vulnerability classes related to an REST endpoint. *Valid values*: `MANUAL, LLM`. *Default value*: `MANUAL`. | +| `wbProbabilityUseDataPool` | __Double__. Specify the probability of using the data pool when sampling test cases. This is for white-box (wb) mode. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.2`. | +| `writeSnapshotTestsIntervalInSeconds` | __Int__. The size (in seconds) of the interval that the snapshots will be printed, if enabled. *Default value*: `3600`. | +| `xss` | __Boolean__. To apply XSS detection as part of security testing. *Default value*: `false`. | From 5554bb4a908e1ee513706e0641999f0e7b75902a Mon Sep 17 00:00:00 2001 From: Alexander Szyrej Date: Mon, 15 Dec 2025 22:46:18 -0300 Subject: [PATCH 5/9] Fixed options.md after running main in ConfigToMarkdown --- docs/options.md | 208 ++++++++++++++++++++++++------------------------ 1 file changed, 104 insertions(+), 104 deletions(-) diff --git a/docs/options.md b/docs/options.md index b9d33b9a4f..ef9aeabf6a 100644 --- a/docs/options.md +++ b/docs/options.md @@ -1,34 +1,34 @@ # Command-Line Options -_EvoMaster_ has several options that can be configured. +_EvoMaster_ has several options that can be configured. Those can be set on the command-line when _EvoMaster_ is started. There are 3 types of options: * __Important__: those are the main options that most users will need to set - and know about. + and know about. * __Internal__: these are low-level tuning options, which most users do not need - to modify. These were mainly introduced when experimenting with - different configurations to maximize the performance of _EvoMaster_. - Some of these options are used to collect more info on the search, to help - debugging issues in _EvoMaster_ itself. - + to modify. These were mainly introduced when experimenting with + different configurations to maximize the performance of _EvoMaster_. + Some of these options are used to collect more info on the search, to help + debugging issues in _EvoMaster_ itself. + * __Experimental__: these are work-in-progress options, for features still under development - and testing. - - -The list of available options can also be displayed by using `--help`, e.g.: - -`java -jar evomaster.jar --help` + and testing. + -Options might also have *constraints*, e.g., a numeric value within a defined range, -or a string being an URL. -In some cases, strings might only be chosen within a specific set of possible values (i.e., an Enum). -If any constraint is not satisfied, _EvoMaster_ will fail with an error message. - -When used, all options need to be prefixed with a `--`, e.g., `--maxTime`. + The list of available options can also be displayed by using `--help`, e.g.: + `java -jar evomaster.jar --help` + + Options might also have *constraints*, e.g., a numeric value within a defined range, + or a string being an URL. + In some cases, strings might only be chosen within a specific set of possible values (i.e., an Enum). + If any constraint is not satisfied, _EvoMaster_ will fail with an error message. + + When used, all options need to be prefixed with a `--`, e.g., `--maxTime`. + ## Important Command-Line Options |Options|Description| @@ -241,88 +241,88 @@ When used, all options need to be prefixed with a `--`, e.g., `--maxTime`. ## Experimental Command-Line Options -| Options | Description | -|--------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `aIClassificationMetrics` | __Enum__. Determines which metric-tracking strategy is used by the AI response classifier. *Valid values*: `TIME_WINDOW, FULL_HISTORY`. *Default value*: `TIME_WINDOW`. | -| `abstractInitializationGeneToMutate` | __Boolean__. During mutation, whether to abstract genes for repeated SQL actions. *Default value*: `false`. | -| `aiClassifierRepairActivation` | __Enum__. Specify how the classification of actions's response will be used to execute a possible repair on the action. *Valid values*: `PROBABILITY, THRESHOLD`. *Default value*: `THRESHOLD`. | -| `aiEncoderType` | __Enum__. The encoding strategy applied to transform raw data to the encoded version. *Valid values*: `RAW, NORMAL, UNIT_NORMAL`. *Default value*: `RAW`. | -| `aiModelForResponseClassification` | __Enum__. Model used to learn input constraints and infer response status before making request. *Valid values*: `NONE, GAUSSIAN, KDE, KNN, NN, GLM, DETERMINISTIC`. *Default value*: `NONE`. | -| `aiResponseClassifierLearningRate` | __Double__. Learning rate controlling the step size during parameter updates in classifiers. Relevant for gradient-based models such as GLM and neural networks. A smaller value ensures stable but slower convergence, while a larger value speeds up training but may cause instability. *Default value*: `0.01`. | -| `aiResponseClassifierMaxStoredSamples` | __Int__. Maximum number of stored samples for classifiers such as KNN and KDE models that rely on retaining encoded inputs. This value specifies the maximum number of samples stored for each endpoint. A higher value can improve classification accuracy by leveraging more historical data, but also increases memory usage. A lower value reduces memory consumption but may limit the classifier’s knowledge base. Typically, it is safe to keep this value between 10,000 and 50,000 when the encoded input vector is usually a list of doubles with a length under 20. Reservoir sampling is applied independently for each endpoint: if this maximum number is exceeded, new samples randomly replace existing ones, ensuring an unbiased selection of preserved data. As an example, for an API with 100 endpoints and an input vector of size 20, a maximum of 10,000 samples per endpoint would require roughly 200 MB of memory. *Default value*: `10000`. | -| `aiResponseClassifierWarmup` | __Int__. Number of training iterations required to update classifier parameters. For example, in the Gaussian model this affects mean and variance updates. For neural network (NN) models, the warm-up should typically be larger than 1000. *Default value*: `10`. | -| `appendToTargetHeuristicsFile` | __Boolean__. Whether should add to an existing target heuristics file, instead of replacing it. It is only used when processFormat is TARGET_HEURISTIC. *Default value*: `false`. | -| `bbProbabilityUseDataPool` | __Double__. Specify the probability of using the data pool when sampling test cases. This is for black-box (bb) mode. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.8`. | -| `breederParentsMin` | __Int__. Breeder GA: minimum number of individuals in parents pool after truncation. *Constraints*: `min=2.0`. *Default value*: `2`. | -| `breederTruncationFraction` | __Double__. Breeder GA: fraction of top individuals to keep in parents pool (truncation). *Constraints*: `probability 0.0-1.0`. *Default value*: `0.5`. | -| `callbackURLHostname` | __String__. HTTP callback verifier hostname. Default is set to 'localhost'. If the SUT is running inside a container (i.e., Docker), 'localhost' will refer to the container. This can be used to change the hostname. *Default value*: `localhost`. | -| `cgaNeighborhoodModel` | __Enum__. Cellular GA: neighborhood model (RING, L5, C9, C13). *Valid values*: `RING, L5, C9, C13`. *Default value*: `RING`. | -| `classificationRepairThreshold` | __Double__. If using THRESHOLD for AI Classification Repair, specify its value. All classifications with probability equal or above such threshold value will be accepted. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.8`. | -| `discoveredInfoRewardedInFitness` | __Boolean__. If there is new discovered information from a test execution, reward it in the fitness function. *Default value*: `false`. | -| `dockerLocalhost` | __Boolean__. Replace references to 'localhost' to point to the actual host machine. Only needed when running EvoMaster inside Docker. *Default value*: `false`. | -| `dpcTargetTestSize` | __Int__. Specify a max size of a test to be targeted when either DPC_INCREASING or DPC_DECREASING is enabled. *Default value*: `1`. | -| `dtoForRequestPayload` | __Boolean__. In REST APIs, when request Content-Type is JSON, POJOs are used instead of raw JSON string. Only available for JVM languages. *Default value*: `false`. | -| `employResourceSizeHandlingStrategy` | __Enum__. Specify a strategy to determinate a number of resources to be manipulated throughout the search. *Valid values*: `NONE, RANDOM, DPC`. *Default value*: `NONE`. | -| `enableAdaptiveResourceStructureMutation` | __Boolean__. Specify whether to decide the resource-based structure mutator and resource to be mutated adaptively based on impacts during focused search.Note that it only works when resource-based solution is enabled for solving REST problem. *Default value*: `false`. | -| `enableCustomizedMethodForMockObjectHandling` | __Boolean__. Whether to apply customized method (i.e., implement 'customizeMockingRPCExternalService' for external services or 'customizeMockingDatabase' for database) to handle mock object. *Default value*: `false`. | -| `enableCustomizedMethodForScheduleTaskHandling` | __Boolean__. Whether to apply customized method (i.e., implement 'customizeScheduleTaskInvocation' for invoking schedule task) to invoke schedule task. *Default value*: `false`. | -| `enableRPCCustomizedTestOutput` | __Boolean__. Whether to enable customized RPC Test output if 'customizeRPCTestOutput' is implemented. *Default value*: `false`. | -| `enableWriteSnapshotTests` | __Boolean__. Enable to print snapshots of the generated tests during the search in an interval defined in snapshotsInterval. *Default value*: `false`. | -| `executiveSummary` | __Boolean__. Generate an executive summary, containing an example of each category of potential faults found.NOTE: This option is only meaningful when used in conjunction with test suite splitting. *Default value*: `false`. | -| `expectationsActive` | __Boolean__. Enable Expectation Generation. If enabled, expectations will be generated. A variable called expectationsMasterSwitch is added to the test suite, with a default value of false. If set to true, an expectation that fails will cause the test case containing it to fail. *Default value*: `false`. | -| `exportTestCasesDuringSeeding` | __Boolean__. Whether to export test cases during seeding as a separate file. *Default value*: `false`. | -| `externalRequestHarvesterNumberOfThreads` | __Int__. Number of threads for external request harvester. No more threads than numbers of processors will be used. *Constraints*: `min=1.0`. *Default value*: `2`. | -| `externalRequestResponseSelectionStrategy` | __Enum__. Harvested external request response selection strategy. *Valid values*: `EXACT, CLOSEST_SAME_DOMAIN, CLOSEST_SAME_PATH, RANDOM`. *Default value*: `EXACT`. | -| `externalServiceIP` | __String__. User provided external service IP. When EvoMaster mocks external services, mock server instances will run on local addresses starting from this provided address. Min value is 127.0.0.4. Lower values like 127.0.0.2 and 127.0.0.3 are reserved. *Constraints*: `regex (?!^0*127(\.0*0){2}\.0*[0123]$)^0*127(\.0*(25[0-5]\|2[0-4][0-9]\|1?[0-9]?[0-9])){3}$`. *Default value*: `127.0.0.4`. | -| `externalServiceIPSelectionStrategy` | __Enum__. Specify a method to select the first external service spoof IP address. *Valid values*: `NONE, DEFAULT, USER, RANDOM`. *Default value*: `NONE`. | -| `generateSqlDataWithDSE` | __Boolean__. Enable EvoMaster to generate SQL data with direct accesses to the database. Use Dynamic Symbolic Execution. *Default value*: `false`. | -| `heuristicsForSQLAdvanced` | __Boolean__. If using SQL heuristics, enable more advanced version. *Default value*: `false`. | -| `heuristicsForRedis` | __Boolean__. Tracking of Redis commands to improve test generation. *Default value*: `false`. | -| `httpOracles` | __Boolean__. Extra checks on HTTP properties in returned responses, used as automated oracles to detect faults. *Default value*: `false`. | -| `initStructureMutationProbability` | __Double__. Probability of applying a mutation that can change the structure of test's initialization if it has. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`. | -| `instrumentMR_NET` | __Boolean__. Execute instrumentation for method replace with category NET. Note: this applies only for languages in which instrumentation is applied at runtime, like Java/Kotlin on the JVM. *Default value*: `false`. | -| `instrumentMR_OPENSEARCH` | __Boolean__. Execute instrumentation for method replace with category OPENSEARCH. Note: this applies only for languages in which instrumentation is applied at runtime, like Java/Kotlin on the JVM. *Default value*: `false`. | -| `instrumentMR_REDIS` | __Boolean__. Execute instrumentation for method replace with category REDIS. Note: this applies only for languages in which instrumentation is applied at runtime, like Java/Kotlin on the JVM. *Default value*: `false`. | -| `languageModelConnector` | __Boolean__. Enable language model connector. *Default value*: `false`. | -| `languageModelConnectorNumberOfThreads` | __Int__. Number of threads for language model connector. No more threads than numbers of processors will be used. *Constraints*: `min=1.0`. *Default value*: `2`. | -| `languageModelName` | __String__. Large-language model name as listed in Ollama. *Default value*: `llama3.2:latest`. | -| `languageModelServerURL` | __String__. Large-language model external service URL. Default is set to Ollama local instance URL. *Default value*: `http://localhost:11434/`. | -| `maxRepairAttemptsInResponseClassification` | __Int__. When the Response Classifier determines an action is going to fail, specify how many attempts will be tried at fixing it. *Constraints*: `min=1.0`. *Default value*: `100`. | -| `maxResourceSize` | __Int__. Specify a max size of resources in a test. 0 means the there is no specified restriction on a number of resources. *Constraints*: `min=0.0`. *Default value*: `0`. | -| `maxSizeDataPool` | __Int__. How much data elements, per key, can be stored in the Data Pool. Once limit is reached, new old will replace old data. *Constraints*: `min=1.0`. *Default value*: `100`. | -| `maxSizeOfExistingDataToSample` | __Int__. Specify a maximum number of existing data in the database to sample in a test when SQL handling is enabled. Note that a negative number means all existing data would be sampled. *Default value*: `-1`. | -| `maxSizeOfHandlingResource` | __Int__. Specify a maximum number of handling (remove/add) resource size at once, e.g., add 3 resource at most. *Constraints*: `min=0.0`. *Default value*: `0`. | -| `maxSizeOfMutatingInitAction` | __Int__. Specify a maximum number of handling (remove/add) init actions at once, e.g., add 3 init actions at most. *Constraints*: `min=0.0`. *Default value*: `0`. | -| `maxTestSizeStrategy` | __Enum__. Specify a strategy to handle a max size of a test. *Valid values*: `SPECIFIED, DPC_INCREASING, DPC_DECREASING`. *Default value*: `SPECIFIED`. | -| `maxTestsPerTestSuite` | __Int__. Specify the maximum number of tests to be generated in one test suite. Note that a negative number presents no limit per test suite. *Default value*: `-1`. | -| `mutationTargetsSelectionStrategy` | __Enum__. Specify a strategy to select targets for evaluating mutation. *Valid values*: `FIRST_NOT_COVERED_TARGET, EXPANDED_UPDATED_NOT_COVERED_TARGET, UPDATED_NOT_COVERED_TARGET`. *Default value*: `FIRST_NOT_COVERED_TARGET`. | -| `onePlusLambdaLambdaOffspringSize` | __Int__. 1+(λ,λ) GA: number of offspring (λ) per generation. *Constraints*: `min=1.0`. *Default value*: `4`. | -| `prematureStopStrategy` | __Enum__. Specify how 'improvement' is defined: either any kind of improvement even if partial (ANY), or at least one new target is fully covered (NEW). *Valid values*: `ANY, NEW`. *Default value*: `NEW`. | -| `probOfHandlingLength` | __Double__. Specify a probability of applying length handling. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`. | -| `probOfHarvestingResponsesFromActualExternalServices` | __Double__. a probability of harvesting actual responses from external services as seeds. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`. | -| `probOfMutatingResponsesBasedOnActualResponse` | __Double__. a probability of mutating mocked responses based on actual responses. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`. | -| `probOfPrioritizingSuccessfulHarvestedActualResponses` | __Double__. a probability of prioritizing to employ successful harvested actual responses from external services as seeds (e.g., 2xx from HTTP external service). *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`. | -| `probOfSamplingScheduleTask` | __Double__. Probability of sampling a new individual with schedule tasks. Note that schedule task is only enabled for RPCProblem. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`. | -| `probOfSmartInitStructureMutator` | __Double__. Specify a probability of applying a smart structure mutator for initialization of the individual. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`. | -| `probabilityAllOptionalsAreOnOrOff` | __Double__. When sampling a new individual, probability that ALL optional choices are ON, or ALL are OFF. The choice between ON and OFF depends on probabilityOfOnVsOffInAllOptionals. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`. | -| `saveMockedResponseAsSeparatedFile` | __Boolean__. Whether to save mocked responses as separated files. *Default value*: `false`. | -| `saveScheduleTaskInvocationAsSeparatedFile` | __Boolean__. Whether to save schedule task invocation as separated files. *Default value*: `false`. | -| `saveTargetHeuristicsPrefixes` | __String__. Prefix specifying which targets to record. Each target can be separated by a comma, such as 'Branch,Line,Success, etc'. It is only used when processFormat is TARGET_HEURISTIC. *Default value*: `Branch`. | -| `seedTestCases` | __Boolean__. Whether to seed EvoMaster with some initial test cases. These test cases will be used and evolved throughout the search process. *Default value*: `false`. | -| `seedTestCasesFormat` | __Enum__. Format of the test cases seeded to EvoMaster. *Valid values*: `POSTMAN`. *Default value*: `POSTMAN`. | -| `seedTestCasesPath` | __String__. File path where the seeded test cases are located. *Default value*: `postman.postman_collection.json`. | -| `ssrf` | __Boolean__. To apply SSRF detection as part of security testing. *Default value*: `false`. | -| `structureMutationProFS` | __Double__. Specify a probability of applying structure mutator during the focused search. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`. | -| `structureMutationProbStrategy` | __Enum__. Specify a strategy to handle a probability of applying structure mutator during the focused search. *Valid values*: `SPECIFIED, SPECIFIED_FS, DPC_TO_SPECIFIED_BEFORE_FS, DPC_TO_SPECIFIED_AFTER_FS, ADAPTIVE_WITH_IMPACT`. *Default value*: `SPECIFIED`. | -| `taintForceSelectionOfGenesWithSpecialization` | __Boolean__. During mutation, force the mutation of genes that have newly discovered specialization from previous fitness evaluations, based on taint analysis. *Default value*: `false`. | -| `targetHeuristicsFile` | __String__. Where the target heuristic values file (if any) is going to be written (in CSV format). It is only used when processFormat is TARGET_HEURISTIC. *Default value*: `targets.csv`. | -| `testResourcePathToSaveMockedResponse` | __String__. Specify test resource path where to save mocked responses as separated files. *Default value*: `""`. | -| `thresholdDistanceForDataPool` | __Int__. Threshold of Levenshtein Distance for key-matching in Data Pool. *Constraints*: `min=0.0`. *Default value*: `2`. | -| `useGlobalTaintInfoProbability` | __Double__. When sampling new individual, check whether to use already existing info on tainted values. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`. | -| `useInsertionForSqlHeuristics` | __Boolean__. Specify whether insertions should be used to calculate SQL heuristics instead of retrieving data from real databases. *Default value*: `false`. | -| `useTestMethodOrder` | __Boolean__. Adds TestMethodOrder annotation for JUnit 5 tests. *Default value*: `false`. | -| `useWeightedSampling` | __Boolean__. When sampling from archive based on targets, decide whether to use weights based on properties of the targets (e.g., a target likely leading to a flag will be sampled less often). *Default value*: `false`. | -| `vulnerableInputClassificationStrategy` | __Enum__. Strategy to classify inputs for potential vulnerability classes related to an REST endpoint. *Valid values*: `MANUAL, LLM`. *Default value*: `MANUAL`. | -| `wbProbabilityUseDataPool` | __Double__. Specify the probability of using the data pool when sampling test cases. This is for white-box (wb) mode. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.2`. | -| `writeSnapshotTestsIntervalInSeconds` | __Int__. The size (in seconds) of the interval that the snapshots will be printed, if enabled. *Default value*: `3600`. | -| `xss` | __Boolean__. To apply XSS detection as part of security testing. *Default value*: `false`. | +|Options|Description| +|---|---| +|`aIClassificationMetrics`| __Enum__. Determines which metric-tracking strategy is used by the AI response classifier. *Valid values*: `TIME_WINDOW, FULL_HISTORY`. *Default value*: `TIME_WINDOW`.| +|`abstractInitializationGeneToMutate`| __Boolean__. During mutation, whether to abstract genes for repeated SQL actions. *Default value*: `false`.| +|`aiClassifierRepairActivation`| __Enum__. Specify how the classification of actions's response will be used to execute a possible repair on the action. *Valid values*: `PROBABILITY, THRESHOLD`. *Default value*: `THRESHOLD`.| +|`aiEncoderType`| __Enum__. The encoding strategy applied to transform raw data to the encoded version. *Valid values*: `RAW, NORMAL, UNIT_NORMAL`. *Default value*: `RAW`.| +|`aiModelForResponseClassification`| __Enum__. Model used to learn input constraints and infer response status before making request. *Valid values*: `NONE, GAUSSIAN, KDE, KNN, NN, GLM, DETERMINISTIC`. *Default value*: `NONE`.| +|`aiResponseClassifierLearningRate`| __Double__. Learning rate controlling the step size during parameter updates in classifiers. Relevant for gradient-based models such as GLM and neural networks. A smaller value ensures stable but slower convergence, while a larger value speeds up training but may cause instability. *Default value*: `0.01`.| +|`aiResponseClassifierMaxStoredSamples`| __Int__. Maximum number of stored samples for classifiers such as KNN and KDE models that rely on retaining encoded inputs. This value specifies the maximum number of samples stored for each endpoint. A higher value can improve classification accuracy by leveraging more historical data, but also increases memory usage. A lower value reduces memory consumption but may limit the classifier’s knowledge base. Typically, it is safe to keep this value between 10,000 and 50,000 when the encoded input vector is usually a list of doubles with a length under 20. Reservoir sampling is applied independently for each endpoint: if this maximum number is exceeded, new samples randomly replace existing ones, ensuring an unbiased selection of preserved data. As an example, for an API with 100 endpoints and an input vector of size 20, a maximum of 10,000 samples per endpoint would require roughly 200 MB of memory. *Default value*: `10000`.| +|`aiResponseClassifierWarmup`| __Int__. Number of training iterations required to update classifier parameters. For example, in the Gaussian model this affects mean and variance updates. For neural network (NN) models, the warm-up should typically be larger than 1000. *Default value*: `10`.| +|`appendToTargetHeuristicsFile`| __Boolean__. Whether should add to an existing target heuristics file, instead of replacing it. It is only used when processFormat is TARGET_HEURISTIC. *Default value*: `false`.| +|`bbProbabilityUseDataPool`| __Double__. Specify the probability of using the data pool when sampling test cases. This is for black-box (bb) mode. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.8`.| +|`breederParentsMin`| __Int__. Breeder GA: minimum number of individuals in parents pool after truncation. *Constraints*: `min=2.0`. *Default value*: `2`.| +|`breederTruncationFraction`| __Double__. Breeder GA: fraction of top individuals to keep in parents pool (truncation). *Constraints*: `probability 0.0-1.0`. *Default value*: `0.5`.| +|`callbackURLHostname`| __String__. HTTP callback verifier hostname. Default is set to 'localhost'. If the SUT is running inside a container (i.e., Docker), 'localhost' will refer to the container. This can be used to change the hostname. *Default value*: `localhost`.| +|`cgaNeighborhoodModel`| __Enum__. Cellular GA: neighborhood model (RING, L5, C9, C13). *Valid values*: `RING, L5, C9, C13`. *Default value*: `RING`.| +|`classificationRepairThreshold`| __Double__. If using THRESHOLD for AI Classification Repair, specify its value. All classifications with probability equal or above such threshold value will be accepted. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.8`.| +|`discoveredInfoRewardedInFitness`| __Boolean__. If there is new discovered information from a test execution, reward it in the fitness function. *Default value*: `false`.| +|`dockerLocalhost`| __Boolean__. Replace references to 'localhost' to point to the actual host machine. Only needed when running EvoMaster inside Docker. *Default value*: `false`.| +|`dpcTargetTestSize`| __Int__. Specify a max size of a test to be targeted when either DPC_INCREASING or DPC_DECREASING is enabled. *Default value*: `1`.| +|`dtoForRequestPayload`| __Boolean__. In REST APIs, when request Content-Type is JSON, POJOs are used instead of raw JSON string. Only available for JVM languages. *Default value*: `false`.| +|`employResourceSizeHandlingStrategy`| __Enum__. Specify a strategy to determinate a number of resources to be manipulated throughout the search. *Valid values*: `NONE, RANDOM, DPC`. *Default value*: `NONE`.| +|`enableAdaptiveResourceStructureMutation`| __Boolean__. Specify whether to decide the resource-based structure mutator and resource to be mutated adaptively based on impacts during focused search.Note that it only works when resource-based solution is enabled for solving REST problem. *Default value*: `false`.| +|`enableCustomizedMethodForMockObjectHandling`| __Boolean__. Whether to apply customized method (i.e., implement 'customizeMockingRPCExternalService' for external services or 'customizeMockingDatabase' for database) to handle mock object. *Default value*: `false`.| +|`enableCustomizedMethodForScheduleTaskHandling`| __Boolean__. Whether to apply customized method (i.e., implement 'customizeScheduleTaskInvocation' for invoking schedule task) to invoke schedule task. *Default value*: `false`.| +|`enableRPCCustomizedTestOutput`| __Boolean__. Whether to enable customized RPC Test output if 'customizeRPCTestOutput' is implemented. *Default value*: `false`.| +|`enableWriteSnapshotTests`| __Boolean__. Enable to print snapshots of the generated tests during the search in an interval defined in snapshotsInterval. *Default value*: `false`.| +|`executiveSummary`| __Boolean__. Generate an executive summary, containing an example of each category of potential faults found.NOTE: This option is only meaningful when used in conjunction with test suite splitting. *Default value*: `false`.| +|`expectationsActive`| __Boolean__. Enable Expectation Generation. If enabled, expectations will be generated. A variable called expectationsMasterSwitch is added to the test suite, with a default value of false. If set to true, an expectation that fails will cause the test case containing it to fail. *Default value*: `false`.| +|`exportTestCasesDuringSeeding`| __Boolean__. Whether to export test cases during seeding as a separate file. *Default value*: `false`.| +|`externalRequestHarvesterNumberOfThreads`| __Int__. Number of threads for external request harvester. No more threads than numbers of processors will be used. *Constraints*: `min=1.0`. *Default value*: `2`.| +|`externalRequestResponseSelectionStrategy`| __Enum__. Harvested external request response selection strategy. *Valid values*: `EXACT, CLOSEST_SAME_DOMAIN, CLOSEST_SAME_PATH, RANDOM`. *Default value*: `EXACT`.| +|`externalServiceIP`| __String__. User provided external service IP. When EvoMaster mocks external services, mock server instances will run on local addresses starting from this provided address. Min value is 127.0.0.4. Lower values like 127.0.0.2 and 127.0.0.3 are reserved. *Constraints*: `regex (?!^0*127(\.0*0){2}\.0*[0123]$)^0*127(\.0*(25[0-5]\|2[0-4][0-9]\|1?[0-9]?[0-9])){3}$`. *Default value*: `127.0.0.4`.| +|`externalServiceIPSelectionStrategy`| __Enum__. Specify a method to select the first external service spoof IP address. *Valid values*: `NONE, DEFAULT, USER, RANDOM`. *Default value*: `NONE`.| +|`generateSqlDataWithDSE`| __Boolean__. Enable EvoMaster to generate SQL data with direct accesses to the database. Use Dynamic Symbolic Execution. *Default value*: `false`.| +|`heuristicsForRedis`| __Boolean__. Tracking of Redis commands to improve test generation. *Default value*: `false`.| +|`heuristicsForSQLAdvanced`| __Boolean__. If using SQL heuristics, enable more advanced version. *Default value*: `false`.| +|`httpOracles`| __Boolean__. Extra checks on HTTP properties in returned responses, used as automated oracles to detect faults. *Default value*: `false`.| +|`initStructureMutationProbability`| __Double__. Probability of applying a mutation that can change the structure of test's initialization if it has. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`.| +|`instrumentMR_NET`| __Boolean__. Execute instrumentation for method replace with category NET. Note: this applies only for languages in which instrumentation is applied at runtime, like Java/Kotlin on the JVM. *Default value*: `false`.| +|`instrumentMR_OPENSEARCH`| __Boolean__. Execute instrumentation for method replace with category OPENSEARCH. Note: this applies only for languages in which instrumentation is applied at runtime, like Java/Kotlin on the JVM. *Default value*: `false`.| +|`instrumentMR_REDIS`| __Boolean__. Execute instrumentation for method replace with category REDIS. Note: this applies only for languages in which instrumentation is applied at runtime, like Java/Kotlin on the JVM. *Default value*: `false`.| +|`languageModelConnector`| __Boolean__. Enable language model connector. *Default value*: `false`.| +|`languageModelConnectorNumberOfThreads`| __Int__. Number of threads for language model connector. No more threads than numbers of processors will be used. *Constraints*: `min=1.0`. *Default value*: `2`.| +|`languageModelName`| __String__. Large-language model name as listed in Ollama. *Default value*: `llama3.2:latest`.| +|`languageModelServerURL`| __String__. Large-language model external service URL. Default is set to Ollama local instance URL. *Default value*: `http://localhost:11434/`.| +|`maxRepairAttemptsInResponseClassification`| __Int__. When the Response Classifier determines an action is going to fail, specify how many attempts will be tried at fixing it. *Constraints*: `min=1.0`. *Default value*: `100`.| +|`maxResourceSize`| __Int__. Specify a max size of resources in a test. 0 means the there is no specified restriction on a number of resources. *Constraints*: `min=0.0`. *Default value*: `0`.| +|`maxSizeDataPool`| __Int__. How much data elements, per key, can be stored in the Data Pool. Once limit is reached, new old will replace old data. *Constraints*: `min=1.0`. *Default value*: `100`.| +|`maxSizeOfExistingDataToSample`| __Int__. Specify a maximum number of existing data in the database to sample in a test when SQL handling is enabled. Note that a negative number means all existing data would be sampled. *Default value*: `-1`.| +|`maxSizeOfHandlingResource`| __Int__. Specify a maximum number of handling (remove/add) resource size at once, e.g., add 3 resource at most. *Constraints*: `min=0.0`. *Default value*: `0`.| +|`maxSizeOfMutatingInitAction`| __Int__. Specify a maximum number of handling (remove/add) init actions at once, e.g., add 3 init actions at most. *Constraints*: `min=0.0`. *Default value*: `0`.| +|`maxTestSizeStrategy`| __Enum__. Specify a strategy to handle a max size of a test. *Valid values*: `SPECIFIED, DPC_INCREASING, DPC_DECREASING`. *Default value*: `SPECIFIED`.| +|`maxTestsPerTestSuite`| __Int__. Specify the maximum number of tests to be generated in one test suite. Note that a negative number presents no limit per test suite. *Default value*: `-1`.| +|`mutationTargetsSelectionStrategy`| __Enum__. Specify a strategy to select targets for evaluating mutation. *Valid values*: `FIRST_NOT_COVERED_TARGET, EXPANDED_UPDATED_NOT_COVERED_TARGET, UPDATED_NOT_COVERED_TARGET`. *Default value*: `FIRST_NOT_COVERED_TARGET`.| +|`onePlusLambdaLambdaOffspringSize`| __Int__. 1+(λ,λ) GA: number of offspring (λ) per generation. *Constraints*: `min=1.0`. *Default value*: `4`.| +|`prematureStopStrategy`| __Enum__. Specify how 'improvement' is defined: either any kind of improvement even if partial (ANY), or at least one new target is fully covered (NEW). *Valid values*: `ANY, NEW`. *Default value*: `NEW`.| +|`probOfHandlingLength`| __Double__. Specify a probability of applying length handling. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`.| +|`probOfHarvestingResponsesFromActualExternalServices`| __Double__. a probability of harvesting actual responses from external services as seeds. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`.| +|`probOfMutatingResponsesBasedOnActualResponse`| __Double__. a probability of mutating mocked responses based on actual responses. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`.| +|`probOfPrioritizingSuccessfulHarvestedActualResponses`| __Double__. a probability of prioritizing to employ successful harvested actual responses from external services as seeds (e.g., 2xx from HTTP external service). *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`.| +|`probOfSamplingScheduleTask`| __Double__. Probability of sampling a new individual with schedule tasks. Note that schedule task is only enabled for RPCProblem. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`.| +|`probOfSmartInitStructureMutator`| __Double__. Specify a probability of applying a smart structure mutator for initialization of the individual. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`.| +|`probabilityAllOptionalsAreOnOrOff`| __Double__. When sampling a new individual, probability that ALL optional choices are ON, or ALL are OFF. The choice between ON and OFF depends on probabilityOfOnVsOffInAllOptionals. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`.| +|`saveMockedResponseAsSeparatedFile`| __Boolean__. Whether to save mocked responses as separated files. *Default value*: `false`.| +|`saveScheduleTaskInvocationAsSeparatedFile`| __Boolean__. Whether to save schedule task invocation as separated files. *Default value*: `false`.| +|`saveTargetHeuristicsPrefixes`| __String__. Prefix specifying which targets to record. Each target can be separated by a comma, such as 'Branch,Line,Success, etc'. It is only used when processFormat is TARGET_HEURISTIC. *Default value*: `Branch`.| +|`seedTestCases`| __Boolean__. Whether to seed EvoMaster with some initial test cases. These test cases will be used and evolved throughout the search process. *Default value*: `false`.| +|`seedTestCasesFormat`| __Enum__. Format of the test cases seeded to EvoMaster. *Valid values*: `POSTMAN`. *Default value*: `POSTMAN`.| +|`seedTestCasesPath`| __String__. File path where the seeded test cases are located. *Default value*: `postman.postman_collection.json`.| +|`ssrf`| __Boolean__. To apply SSRF detection as part of security testing. *Default value*: `false`.| +|`structureMutationProFS`| __Double__. Specify a probability of applying structure mutator during the focused search. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`.| +|`structureMutationProbStrategy`| __Enum__. Specify a strategy to handle a probability of applying structure mutator during the focused search. *Valid values*: `SPECIFIED, SPECIFIED_FS, DPC_TO_SPECIFIED_BEFORE_FS, DPC_TO_SPECIFIED_AFTER_FS, ADAPTIVE_WITH_IMPACT`. *Default value*: `SPECIFIED`.| +|`taintForceSelectionOfGenesWithSpecialization`| __Boolean__. During mutation, force the mutation of genes that have newly discovered specialization from previous fitness evaluations, based on taint analysis. *Default value*: `false`.| +|`targetHeuristicsFile`| __String__. Where the target heuristic values file (if any) is going to be written (in CSV format). It is only used when processFormat is TARGET_HEURISTIC. *Default value*: `targets.csv`.| +|`testResourcePathToSaveMockedResponse`| __String__. Specify test resource path where to save mocked responses as separated files. *Default value*: `""`.| +|`thresholdDistanceForDataPool`| __Int__. Threshold of Levenshtein Distance for key-matching in Data Pool. *Constraints*: `min=0.0`. *Default value*: `2`.| +|`useGlobalTaintInfoProbability`| __Double__. When sampling new individual, check whether to use already existing info on tainted values. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.0`.| +|`useInsertionForSqlHeuristics`| __Boolean__. Specify whether insertions should be used to calculate SQL heuristics instead of retrieving data from real databases. *Default value*: `false`.| +|`useTestMethodOrder`| __Boolean__. Adds TestMethodOrder annotation for JUnit 5 tests. *Default value*: `false`.| +|`useWeightedSampling`| __Boolean__. When sampling from archive based on targets, decide whether to use weights based on properties of the targets (e.g., a target likely leading to a flag will be sampled less often). *Default value*: `false`.| +|`vulnerableInputClassificationStrategy`| __Enum__. Strategy to classify inputs for potential vulnerability classes related to an REST endpoint. *Valid values*: `MANUAL, LLM`. *Default value*: `MANUAL`.| +|`wbProbabilityUseDataPool`| __Double__. Specify the probability of using the data pool when sampling test cases. This is for white-box (wb) mode. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.2`.| +|`writeSnapshotTestsIntervalInSeconds`| __Int__. The size (in seconds) of the interval that the snapshots will be printed, if enabled. *Default value*: `3600`.| +|`xss`| __Boolean__. To apply XSS detection as part of security testing. *Default value*: `false`.| From 34f22147cbbc379dc828bb1b1ac6f31db06fa59b Mon Sep 17 00:00:00 2001 From: Alexander Szyrej Date: Tue, 23 Dec 2025 03:42:53 -0300 Subject: [PATCH 6/9] minor refactor related to ReflectionBasedRedisClient --- .../client/java/controller/SutHandler.java | 3 ++- .../controller/internal/SutController.java | 3 ++- .../internal/db/redis/RedisHandler.java | 20 +++++++++---------- ...t.java => ReflectionBasedRedisClient.java} | 16 +++++++-------- .../db/redis/RedisHandlerIntegrationTest.java | 6 +++--- .../spring/rest/redis/RedisController.java | 7 +++---- 6 files changed, 28 insertions(+), 27 deletions(-) rename client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/{RedisClient.java => ReflectionBasedRedisClient.java} (89%) diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/SutHandler.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/SutHandler.java index 5ee0cc89df..4b835548a9 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/SutHandler.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/SutHandler.java @@ -5,6 +5,7 @@ import org.evomaster.client.java.controller.api.dto.database.operations.MongoInsertionDto; import org.evomaster.client.java.controller.api.dto.database.operations.MongoInsertionResultsDto; import org.evomaster.client.java.controller.api.dto.problem.rpc.ScheduleTaskInvocationResultDto; +import org.evomaster.client.java.controller.redis.ReflectionBasedRedisClient; import org.evomaster.client.java.sql.DbCleaner; import org.evomaster.client.java.sql.DbSpecification; @@ -181,7 +182,7 @@ default void extractRPCSchema(){} default Object getOpenSearchConnection() {return null;} - default Object getRedisConnection() {return null;} + default ReflectionBasedRedisClient getRedisConnection() {return null;} /** *

diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/internal/SutController.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/internal/SutController.java index bc68ce9ec8..db39553a65 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/internal/SutController.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/internal/SutController.java @@ -30,6 +30,7 @@ import org.evomaster.client.java.controller.api.dto.problem.rpc.RPCTestDto; import org.evomaster.client.java.controller.internal.db.OpenSearchHandler; import org.evomaster.client.java.controller.internal.db.redis.RedisHandler; +import org.evomaster.client.java.controller.redis.ReflectionBasedRedisClient; import org.evomaster.client.java.sql.DbCleaner; import org.evomaster.client.java.sql.SqlScriptRunner; import org.evomaster.client.java.sql.SqlScriptRunnerCached; @@ -350,7 +351,7 @@ public final void initOpenSearchHandler() { } public final void initRedisHandler() { - Object connection = getRedisConnection(); + ReflectionBasedRedisClient connection = getRedisConnection(); redisHandler.setRedisClient(connection); List list = getAdditionalInfoList(); diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/internal/db/redis/RedisHandler.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/internal/db/redis/RedisHandler.java index 1bc8746cc8..e41df05736 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/internal/db/redis/RedisHandler.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/internal/db/redis/RedisHandler.java @@ -1,7 +1,7 @@ package org.evomaster.client.java.controller.internal.db.redis; import org.evomaster.client.java.controller.internal.TaintHandlerExecutionTracer; -import org.evomaster.client.java.controller.redis.RedisClient; +import org.evomaster.client.java.controller.redis.ReflectionBasedRedisClient; import org.evomaster.client.java.controller.redis.RedisHeuristicsCalculator; import org.evomaster.client.java.controller.redis.RedisInfo; import org.evomaster.client.java.instrumentation.RedisCommand; @@ -32,9 +32,9 @@ public class RedisHandler { private volatile boolean calculateHeuristics; /** - * The client must be created through a connection factory. + * The client must be created given both host and port for Redis DB. */ - private Object redisClient = null; + private ReflectionBasedRedisClient redisClient = null; private final RedisHeuristicsCalculator calculator = new RedisHeuristicsCalculator(new TaintHandlerExecutionTracer()); @@ -68,7 +68,7 @@ public List getEvaluatedRedisCommands() { operations.stream() .filter(command -> command.getType().shouldCalculateHeuristic()) .forEach(redisCommand -> { - RedisDistanceWithMetrics distanceWithMetrics = computeDistance(redisCommand, (RedisClient) redisClient); + RedisDistanceWithMetrics distanceWithMetrics = computeDistance(redisCommand, redisClient); evaluatedRedisCommands.add(new RedisCommandEvaluation(redisCommand, distanceWithMetrics)); }); operations.clear(); @@ -76,7 +76,7 @@ public List getEvaluatedRedisCommands() { return evaluatedRedisCommands; } - private RedisDistanceWithMetrics computeDistance(RedisCommand redisCommand, RedisClient redisClient) { + private RedisDistanceWithMetrics computeDistance(RedisCommand redisCommand, ReflectionBasedRedisClient redisClient) { RedisCommand.RedisCommandType type = redisCommand.getType(); try { switch (type) { @@ -122,7 +122,7 @@ private RedisDistanceWithMetrics computeDistance(RedisCommand redisCommand, Redi } } - private List createRedisInfoForIntersection(List keys, RedisClient redisClient) { + private List createRedisInfoForIntersection(List keys, ReflectionBasedRedisClient redisClient) { List redisData = new ArrayList<>(); keys.forEach( key -> redisData.add(new RedisInfo(key, redisClient.getType(key), redisClient.getSetMembers(key)) @@ -130,7 +130,7 @@ private List createRedisInfoForIntersection(List keys, RedisC return redisData; } - private List createRedisInfoForAllKeys(RedisClient redisClient) { + private List createRedisInfoForAllKeys(ReflectionBasedRedisClient redisClient) { Set keys = redisClient.getAllKeys(); List redisData = new ArrayList<>(); keys.forEach( @@ -139,21 +139,21 @@ private List createRedisInfoForAllKeys(RedisClient redisClient) { return redisData; } - private List createRedisInfoForKeysByType(String type, RedisClient redisClient) { + private List createRedisInfoForKeysByType(String type, ReflectionBasedRedisClient redisClient) { Set keys = redisClient.getKeysByType(type); List redisData = new ArrayList<>(); keys.forEach(key -> redisData.add(new RedisInfo(key))); return redisData; } - private List createRedisInfoForKeysByField(String field, RedisClient redisClient) { + private List createRedisInfoForKeysByField(String field, ReflectionBasedRedisClient redisClient) { Set keys = redisClient.getKeysByType(REDIS_HASH_TYPE); List redisData = new ArrayList<>(); keys.forEach(key -> redisData.add(new RedisInfo(key, redisClient.getHashFields(key)))); return redisData; } - public void setRedisClient(Object redisClient) { + public void setRedisClient(ReflectionBasedRedisClient redisClient) { this.redisClient = redisClient; } } diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisClient.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/ReflectionBasedRedisClient.java similarity index 89% rename from client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisClient.java rename to client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/ReflectionBasedRedisClient.java index ea30467dbf..8cd9dd64f1 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisClient.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/ReflectionBasedRedisClient.java @@ -10,13 +10,13 @@ * RedisClient that uses Lettuce dynamically via reflection, avoiding * compile-time dependency on Spring or Lettuce. */ -public class RedisClient { +public class ReflectionBasedRedisClient { - private final Object redisClient; // io.lettuce.core.RedisClient + private final Object lettuceClient; // io.lettuce.core.RedisClient private final Object connection; // io.lettuce.core.api.StatefulRedisConnection private final Object syncCommands; // io.lettuce.core.api.sync.RedisCommands - public RedisClient(String host, int port) { + public ReflectionBasedRedisClient(String host, int port) { try { Class redisClientClass = Class.forName("io.lettuce.core.RedisClient"); Class redisURIClass = Class.forName("io.lettuce.core.RedisURI"); @@ -27,10 +27,10 @@ public RedisClient(String host, int port) { SimpleLogger.debug("Connecting to Redis with PORT: " + port); Method createClient = redisClientClass.getMethod("create", redisURIClass); - this.redisClient = createClient.invoke(null, uri); + this.lettuceClient = createClient.invoke(null, uri); Method connectMethod = redisClientClass.getMethod("connect"); - this.connection = connectMethod.invoke(redisClient); + this.connection = connectMethod.invoke(lettuceClient); Class statefulConnClass = Class.forName("io.lettuce.core.api.StatefulRedisConnection"); Method syncMethod = statefulConnClass.getMethod("sync"); @@ -47,9 +47,9 @@ public void close() { Method close = connection.getClass().getMethod("close"); close.invoke(connection); } - if (redisClient != null) { - Method shutdown = redisClient.getClass().getMethod("shutdown"); - shutdown.invoke(redisClient); + if (lettuceClient != null) { + Method shutdown = lettuceClient.getClass().getMethod("shutdown"); + shutdown.invoke(lettuceClient); } } catch (Exception ignored) {} } 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 ce1138dda0..95e1be94a9 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 @@ -1,7 +1,7 @@ package org.evomaster.client.java.controller.internal.db.redis; import org.evomaster.client.java.instrumentation.RedisCommand; -import org.evomaster.client.java.controller.redis.RedisClient; +import org.evomaster.client.java.controller.redis.ReflectionBasedRedisClient; import org.junit.jupiter.api.*; import org.testcontainers.containers.GenericContainer; import org.testcontainers.utility.DockerImageName; @@ -15,7 +15,7 @@ class RedisHandlerIntegrationTest { private static final int REDIS_PORT = 6379; private GenericContainer redisContainer; - private RedisClient client; + private ReflectionBasedRedisClient client; private RedisHandler handler; private int port; @@ -27,7 +27,7 @@ void setupContainer() { port = redisContainer.getMappedPort(REDIS_PORT); - client = new RedisClient("localhost", port); + client = new ReflectionBasedRedisClient("localhost", port); } @BeforeEach diff --git a/core-tests/e2e-tests/spring/spring-rest-redis/src/test/java/com/foo/spring/rest/redis/RedisController.java b/core-tests/e2e-tests/spring/spring-rest-redis/src/test/java/com/foo/spring/rest/redis/RedisController.java index f3dfaec53a..87f9562326 100644 --- a/core-tests/e2e-tests/spring/spring-rest-redis/src/test/java/com/foo/spring/rest/redis/RedisController.java +++ b/core-tests/e2e-tests/spring/spring-rest-redis/src/test/java/com/foo/spring/rest/redis/RedisController.java @@ -3,12 +3,11 @@ import org.evomaster.client.java.controller.EmbeddedSutController; import org.evomaster.client.java.controller.api.dto.auth.AuthenticationDto; import org.evomaster.client.java.controller.api.dto.SutInfoDto; -import org.evomaster.client.java.controller.redis.RedisClient; +import org.evomaster.client.java.controller.redis.ReflectionBasedRedisClient; import org.evomaster.client.java.sql.DbSpecification; import org.evomaster.client.java.controller.problem.ProblemInfo; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.data.redis.connection.RedisConnectionFactory; import org.testcontainers.containers.GenericContainer; import org.evomaster.client.java.controller.problem.RestProblem; import redis.clients.jedis.Jedis; @@ -113,7 +112,7 @@ protected int getSutPort() { } @Override - public RedisClient getRedisConnection() { - return new RedisClient(this.host, this.port); + public ReflectionBasedRedisClient getRedisConnection() { + return new ReflectionBasedRedisClient(this.host, this.port); } } From dca49fd331124a36609a9017e71db6753bf16d62 Mon Sep 17 00:00:00 2001 From: Alexander Szyrej Date: Fri, 9 Jan 2026 18:52:27 -0300 Subject: [PATCH 7/9] changes requested in PR --- .../redis/RedisHeuristicsCalculator.java | 4 +- .../redis/ReflectionBasedRedisClient.java | 42 ++++++++++++------- .../spring/spring-rest-redis/pom.xml | 2 +- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisHeuristicsCalculator.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisHeuristicsCalculator.java index 1c5917a01b..18e3910692 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisHeuristicsCalculator.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/RedisHeuristicsCalculator.java @@ -195,10 +195,10 @@ private RedisDistanceWithMetrics calculateDistanceForFieldInHash( */ private double calculateDistanceForField(String targetField, Set fields) { if (fields.isEmpty()) { - return Long.MAX_VALUE; + return Double.MAX_VALUE; } - double minDist = Long.MAX_VALUE; + double minDist = Double.MAX_VALUE; for (String field : fields) { try { diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/ReflectionBasedRedisClient.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/ReflectionBasedRedisClient.java index 8cd9dd64f1..ec10f6c7b6 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/ReflectionBasedRedisClient.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/redis/ReflectionBasedRedisClient.java @@ -16,24 +16,38 @@ public class ReflectionBasedRedisClient { private final Object connection; // io.lettuce.core.api.StatefulRedisConnection private final Object syncCommands; // io.lettuce.core.api.sync.RedisCommands + private static final String CLOSE_METHOD = "close"; + private static final String CONNECT_METHOD = "connect"; + private static final String CREATE_METHOD = "create"; + private static final String FLUSHALL_METHOD = "flushall"; + private static final String GET_METHOD = "get"; + private static final String HGETALL_METHOD = "hgetall"; + private static final String HSET_METHOD = "hset"; + private static final String KEYS_METHOD = "keys"; + private static final String SET_METHOD = "set"; + private static final String SHUTDOWN_METHOD = "shutdown"; + private static final String SMEMBERS_METHOD = "smembers"; + private static final String SYNC_METHOD = "sync"; + private static final String TYPE_METHOD = "type"; + public ReflectionBasedRedisClient(String host, int port) { try { Class redisClientClass = Class.forName("io.lettuce.core.RedisClient"); Class redisURIClass = Class.forName("io.lettuce.core.RedisURI"); - Method createUri = redisURIClass.getMethod("create", String.class); + Method createUri = redisURIClass.getMethod(CREATE_METHOD, String.class); Object uri = createUri.invoke(null, "redis://" + host + ":" + port); SimpleLogger.debug("Connecting to Redis with PORT: " + port); - Method createClient = redisClientClass.getMethod("create", redisURIClass); + Method createClient = redisClientClass.getMethod(CREATE_METHOD, redisURIClass); this.lettuceClient = createClient.invoke(null, uri); - Method connectMethod = redisClientClass.getMethod("connect"); + Method connectMethod = redisClientClass.getMethod(CONNECT_METHOD); this.connection = connectMethod.invoke(lettuceClient); Class statefulConnClass = Class.forName("io.lettuce.core.api.StatefulRedisConnection"); - Method syncMethod = statefulConnClass.getMethod("sync"); + Method syncMethod = statefulConnClass.getMethod(SYNC_METHOD); this.syncCommands = syncMethod.invoke(connection); } catch (Exception e) { @@ -44,11 +58,11 @@ public ReflectionBasedRedisClient(String host, int port) { public void close() { try { if (connection != null) { - Method close = connection.getClass().getMethod("close"); + Method close = connection.getClass().getMethod(CLOSE_METHOD); close.invoke(connection); } if (lettuceClient != null) { - Method shutdown = lettuceClient.getClass().getMethod("shutdown"); + Method shutdown = lettuceClient.getClass().getMethod(SHUTDOWN_METHOD); shutdown.invoke(lettuceClient); } } catch (Exception ignored) {} @@ -56,17 +70,17 @@ public void close() { /** Equivalent to SET key value */ public void setValue(String key, String value) { - invoke("set", key, value); + invoke(SET_METHOD, key, value); } /** Equivalent to GET key */ public String getValue(String key) { - return (String) invoke("get", key); + return (String) invoke(GET_METHOD, key); } /** Equivalent to KEYS * */ public Set getAllKeys() { - Object result = invoke("keys", "*"); + Object result = invoke(KEYS_METHOD, "*"); if (result instanceof Collection) return new HashSet<>((Collection) result); return Collections.emptySet(); @@ -74,18 +88,18 @@ public Set getAllKeys() { /** Equivalent to TYPE key */ public String getType(String key) { - Object result = invoke("type", key); + Object result = invoke(TYPE_METHOD, key); return result != null ? result.toString() : null; } /** HSET key field value */ public void hashSet(String key, String field, String value) { - invoke("hset", key, field, value); + invoke(HSET_METHOD, key, field, value); } /** SMEMBERS key */ public Set getSetMembers(String key) { - Object result = invoke("smembers", key); + Object result = invoke(SMEMBERS_METHOD, key); if (result instanceof Collection) return new HashSet<>((Collection) result); return Collections.emptySet(); @@ -123,11 +137,11 @@ public Set getKeysByType(String expectedType) { } public void flushAll() { - invoke("flushall"); + invoke(FLUSHALL_METHOD); } public Map getHashFields(String key) { - Object result = invoke("hgetall", key); + Object result = invoke(HGETALL_METHOD, key); return (Map) result; } } \ No newline at end of file diff --git a/core-tests/e2e-tests/spring/spring-rest-redis/pom.xml b/core-tests/e2e-tests/spring/spring-rest-redis/pom.xml index 02362ec380..dabe80eb88 100644 --- a/core-tests/e2e-tests/spring/spring-rest-redis/pom.xml +++ b/core-tests/e2e-tests/spring/spring-rest-redis/pom.xml @@ -6,7 +6,7 @@ evomaster-e2e-tests-spring org.evomaster - 4.0.1-SNAPSHOT + 5.0.1-SNAPSHOT evomaster-e2e-tests-spring-rest-redis From fe584f8db467117832a1ee720b76e387ea6d591a Mon Sep 17 00:00:00 2001 From: Alexander Szyrej Date: Mon, 12 Jan 2026 18:03:39 -0300 Subject: [PATCH 8/9] Refactor jedis version to root POM --- core-tests/e2e-tests/spring/spring-rest-redis/pom.xml | 1 - pom.xml | 8 ++++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/core-tests/e2e-tests/spring/spring-rest-redis/pom.xml b/core-tests/e2e-tests/spring/spring-rest-redis/pom.xml index dabe80eb88..edd9c9e352 100644 --- a/core-tests/e2e-tests/spring/spring-rest-redis/pom.xml +++ b/core-tests/e2e-tests/spring/spring-rest-redis/pom.xml @@ -58,7 +58,6 @@ redis.clients jedis - 5.1.0 io.springfox diff --git a/pom.xml b/pom.xml index 98c90432fe..253a5ba0c8 100644 --- a/pom.xml +++ b/pom.xml @@ -152,6 +152,7 @@ 1.0.0 2.6.6 6.1.4.RELEASE + 5.1.0 @@ -584,6 +585,13 @@ ${io.lettuce.core.version} + + + redis.clients + jedis + ${redis.clients.jedis.version} + + org.opensearch.client From b6c70f65bc8b2905fbe32620ac37c43850d118f5 Mon Sep 17 00:00:00 2001 From: Juan Pablo Galeotti Date: Fri, 16 Jan 2026 13:12:26 -0300 Subject: [PATCH 9/9] clarify comments and add explanation for schema metadata extraction in Mongo handler initialization --- .../client/java/controller/internal/SutController.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/internal/SutController.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/internal/SutController.java index db39553a65..0b8a14b8f9 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/internal/SutController.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/internal/SutController.java @@ -326,10 +326,13 @@ public final void initSqlHandler() { } public final void initMongoHandler() { - // This is needed because the replacement use to get this info occurs during the start of the SUT. Object connection = getMongoConnection(); mongoHandler.setMongoClient(connection); + // Spring MongoDB repositories capture document type metadata during SUT startup. + // We must extract this schema info from MappingMongoEntityInformation instances + // created during initialization, as this mapping is not accessible from the + // standard MongoDB driver collections later on. List list = getAdditionalInfoList(); if(!list.isEmpty()) { AdditionalInfo last = list.get(list.size() - 1);