From 7e195b087ad3de525b2e4df3bb09d82b01b0c0ca Mon Sep 17 00:00:00 2001 From: Agustina Aldasoro Date: Fri, 20 Mar 2026 13:48:35 -0300 Subject: [PATCH 1/3] Filter blank failedWhere Queries from mutator We were sending empty strings as a valid query --- .../evomaster/core/problem/api/service/ApiWsStructureMutator.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/api/service/ApiWsStructureMutator.kt b/core/src/main/kotlin/org/evomaster/core/problem/api/service/ApiWsStructureMutator.kt index e2085301bf..fefc12a420 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/api/service/ApiWsStructureMutator.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/api/service/ApiWsStructureMutator.kt @@ -277,6 +277,7 @@ abstract class ApiWsStructureMutator : StructureMutator() { val oldSqlActions = mutableListOf().plus(ind.seeInitializingActions()) val failedWhereQueries = evaluatedIndividual.fitness.getViewOfAggregatedFailedWhereQueries() + .filter { it.isNotBlank() } val addedSqlInsertions = handleFailedWhereSQL(ind, fw, failedWhereQueries, mutatedGenes, sampler) ind.repairInitializationActions(randomness) From 063753703d60469da93149e448f8918aab8aa59e Mon Sep 17 00:00:00 2001 From: Agustina Aldasoro Date: Thu, 9 Apr 2026 09:03:59 -0300 Subject: [PATCH 2/3] Add tests --- .../evomaster/core/search/FitnessValueTest.kt | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/core/src/test/kotlin/org/evomaster/core/search/FitnessValueTest.kt b/core/src/test/kotlin/org/evomaster/core/search/FitnessValueTest.kt index b7ce647f0f..d518524071 100644 --- a/core/src/test/kotlin/org/evomaster/core/search/FitnessValueTest.kt +++ b/core/src/test/kotlin/org/evomaster/core/search/FitnessValueTest.kt @@ -5,6 +5,8 @@ import org.evomaster.client.java.controller.api.dto.BootTimeInfoDto import org.evomaster.client.java.controller.api.dto.TargetInfoDto import org.evomaster.client.java.instrumentation.shared.ObjectiveNaming import org.evomaster.core.search.service.IdMapper +import org.evomaster.core.sql.DatabaseExecution +import org.evomaster.core.sql.SqlExecutionInfo import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.Test @@ -123,4 +125,37 @@ class FitnessValueTest { assertEquals(3, linesInfo.searchTime) } + @Test + fun testAggregatedFailedWhereQueriesExcludesBlankEntries() { + val fv = FitnessValue(1.0) + + val execution = DatabaseExecution( + queriedData = emptyMap(), + updatedData = emptyMap(), + insertedData = emptyMap(), + failedWhere = emptyMap(), + deletedData = emptyList(), + numberOfSqlCommands = 3, + sqlParseFailureCount = 0, + executionInfo = listOf( + SqlExecutionInfo("SELECT * FROM foo WHERE id = 1", false, 10L), + SqlExecutionInfo("", false, 5L), + SqlExecutionInfo(" ", false, 5L), + SqlExecutionInfo("SELECT * FROM bar WHERE name = 'x'", false, 8L) + ) + ) + fv.setDatabaseExecution(0, execution) + fv.aggregateDatabaseData() + + val allQueries = fv.getViewOfAggregatedFailedWhereQueries() + assertEquals(4, allQueries.size) + + // Simulate the filter applied in ApiWsStructureMutator before sending queries to the solver + val nonBlankQueries = allQueries.filter { it.isNotBlank() } + assertEquals(2, nonBlankQueries.size) + assertTrue(nonBlankQueries.none { it.isBlank() }) + assertTrue(nonBlankQueries.contains("SELECT * FROM foo WHERE id = 1")) + assertTrue(nonBlankQueries.contains("SELECT * FROM bar WHERE name = 'x'")) + } + } \ No newline at end of file From b5f0ffa355f495c653e5264d624cc7a12b888681 Mon Sep 17 00:00:00 2001 From: Agustina Aldasoro Date: Wed, 15 Apr 2026 20:45:00 -0300 Subject: [PATCH 3/3] Move the fix to the correct function --- .../api/service/ApiWsStructureMutator.kt | 1 - .../org/evomaster/core/search/FitnessValue.kt | 10 ++- .../evomaster/core/search/FitnessValueTest.kt | 68 +++++++++++++++---- 3 files changed, 64 insertions(+), 15 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/api/service/ApiWsStructureMutator.kt b/core/src/main/kotlin/org/evomaster/core/problem/api/service/ApiWsStructureMutator.kt index fefc12a420..e2085301bf 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/api/service/ApiWsStructureMutator.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/api/service/ApiWsStructureMutator.kt @@ -277,7 +277,6 @@ abstract class ApiWsStructureMutator : StructureMutator() { val oldSqlActions = mutableListOf().plus(ind.seeInitializingActions()) val failedWhereQueries = evaluatedIndividual.fitness.getViewOfAggregatedFailedWhereQueries() - .filter { it.isNotBlank() } val addedSqlInsertions = handleFailedWhereSQL(ind, fw, failedWhereQueries, mutatedGenes, sampler) ind.repairInitializationActions(randomness) diff --git a/core/src/main/kotlin/org/evomaster/core/search/FitnessValue.kt b/core/src/main/kotlin/org/evomaster/core/search/FitnessValue.kt index b3c25961f9..42f773ccf5 100644 --- a/core/src/main/kotlin/org/evomaster/core/search/FitnessValue.kt +++ b/core/src/main/kotlin/org/evomaster/core/search/FitnessValue.kt @@ -152,7 +152,15 @@ class FitnessValue( aggregatedFailedWhereQueries.clear() aggregatedFailedWhereQueries.addAll( - databaseExecutions.values.flatMap { a -> a.executionInfo }.map{ b -> b.sqlCommand } + databaseExecutions.values + // Only executions that actually had failing WHERE clauses are relevant; + // collecting from all executions would include unrelated INSERT/UPDATE/DELETE/etc. + .filter { it.failedWhere.isNotEmpty() } + .flatMap { it.executionInfo } + .map { it.sqlCommand } + // JSQLParser >= 4.9 may produce empty-string SQL commands (it used to throw, now + // parses "" to null). Guard here at the source rather than at every call site. + .filter { it.isNotBlank() } ) } fun aggregateMongoDatabaseData(){ diff --git a/core/src/test/kotlin/org/evomaster/core/search/FitnessValueTest.kt b/core/src/test/kotlin/org/evomaster/core/search/FitnessValueTest.kt index d518524071..483974dbb1 100644 --- a/core/src/test/kotlin/org/evomaster/core/search/FitnessValueTest.kt +++ b/core/src/test/kotlin/org/evomaster/core/search/FitnessValueTest.kt @@ -7,6 +7,7 @@ import org.evomaster.client.java.instrumentation.shared.ObjectiveNaming import org.evomaster.core.search.service.IdMapper import org.evomaster.core.sql.DatabaseExecution import org.evomaster.core.sql.SqlExecutionInfo +import org.evomaster.core.sql.schema.TableId import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.Test @@ -126,36 +127,77 @@ class FitnessValueTest { } @Test - fun testAggregatedFailedWhereQueriesExcludesBlankEntries() { + fun testAggregatedFailedWhereQueriesOnlyFromExecutionsWithFailedWhere() { val fv = FitnessValue(1.0) - val execution = DatabaseExecution( + val tableId = TableId("foo") + + // Execution that has a failing WHERE clause — its queries should be collected + val executionWithFailedWhere = DatabaseExecution( + queriedData = emptyMap(), + updatedData = emptyMap(), + insertedData = emptyMap(), + failedWhere = mapOf(tableId to setOf("id")), + deletedData = emptyList(), + numberOfSqlCommands = 1, + sqlParseFailureCount = 0, + executionInfo = listOf( + SqlExecutionInfo("SELECT * FROM foo WHERE id = 1", false, 10L) + ) + ) + + // Execution with no failing WHERE clause — its queries must NOT be collected, + // even though it has executionInfo entries + val executionWithoutFailedWhere = DatabaseExecution( queriedData = emptyMap(), updatedData = emptyMap(), insertedData = emptyMap(), failedWhere = emptyMap(), deletedData = emptyList(), + numberOfSqlCommands = 1, + sqlParseFailureCount = 0, + executionInfo = listOf( + SqlExecutionInfo("INSERT INTO bar VALUES (1)", false, 5L) + ) + ) + + fv.setDatabaseExecution(0, executionWithFailedWhere) + fv.setDatabaseExecution(1, executionWithoutFailedWhere) + fv.aggregateDatabaseData() + + val queries = fv.getViewOfAggregatedFailedWhereQueries() + assertEquals(1, queries.size) + assertTrue(queries.contains("SELECT * FROM foo WHERE id = 1")) + } + + @Test + fun testAggregatedFailedWhereQueriesExcludesBlankSqlCommands() { + val fv = FitnessValue(1.0) + + val tableId = TableId("foo") + + // JSQLParser >= 4.9 can produce empty-string SQL commands; they must be filtered out + // at the source in aggregateDatabaseData() rather than at every call site + val execution = DatabaseExecution( + queriedData = emptyMap(), + updatedData = emptyMap(), + insertedData = emptyMap(), + failedWhere = mapOf(tableId to setOf("id")), + deletedData = emptyList(), numberOfSqlCommands = 3, sqlParseFailureCount = 0, executionInfo = listOf( SqlExecutionInfo("SELECT * FROM foo WHERE id = 1", false, 10L), SqlExecutionInfo("", false, 5L), - SqlExecutionInfo(" ", false, 5L), - SqlExecutionInfo("SELECT * FROM bar WHERE name = 'x'", false, 8L) + SqlExecutionInfo(" ", false, 5L) ) ) fv.setDatabaseExecution(0, execution) fv.aggregateDatabaseData() - val allQueries = fv.getViewOfAggregatedFailedWhereQueries() - assertEquals(4, allQueries.size) - - // Simulate the filter applied in ApiWsStructureMutator before sending queries to the solver - val nonBlankQueries = allQueries.filter { it.isNotBlank() } - assertEquals(2, nonBlankQueries.size) - assertTrue(nonBlankQueries.none { it.isBlank() }) - assertTrue(nonBlankQueries.contains("SELECT * FROM foo WHERE id = 1")) - assertTrue(nonBlankQueries.contains("SELECT * FROM bar WHERE name = 'x'")) + val queries = fv.getViewOfAggregatedFailedWhereQueries() + assertEquals(1, queries.size) + assertTrue(queries.contains("SELECT * FROM foo WHERE id = 1")) } } \ No newline at end of file