From 699e0d9e41465482339f3aa703add6d0f5ca4285 Mon Sep 17 00:00:00 2001 From: aschenzle Date: Thu, 10 Sep 2026 21:57:13 -0700 Subject: [PATCH] DynamoDB insertion output generation. --- .../controller/dynamodb/dsl/DynamoDbDsl.java | 17 +++ .../dynamodb/dsl/DynamoDbDslTest.java | 16 +++ .../evomaster/core/output/DynamoDbWriter.kt | 67 ++++++++++++ .../core/output/service/ApiTestCaseWriter.kt | 21 ++++ .../output/service/GraphQLTestCaseWriter.kt | 1 + .../output/service/HttpWsTestCaseWriter.kt | 2 + .../core/output/service/NoTestCaseWriter.kt | 3 +- .../core/output/service/RPCTestCaseWriter.kt | 3 + .../core/output/service/RestTestCaseWriter.kt | 3 + .../core/output/service/TestCaseWriter.kt | 12 +- .../core/output/service/TestSuiteWriter.kt | 7 ++ .../core/output/service/WebTestCaseWriter.kt | 2 + .../org/evomaster/core/search/Solution.kt | 5 + .../core/search/action/EvaluatedAction.kt | 6 +- .../core/output/DynamoDbWriterTest.kt | 103 ++++++++++++++++++ 15 files changed, 263 insertions(+), 5 deletions(-) create mode 100644 core/src/main/kotlin/org/evomaster/core/output/DynamoDbWriter.kt create mode 100644 core/src/test/kotlin/org/evomaster/core/output/DynamoDbWriterTest.kt diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/dynamodb/dsl/DynamoDbDsl.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/dynamodb/dsl/DynamoDbDsl.java index 43e1e6d7ac..957b94f21d 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/dynamodb/dsl/DynamoDbDsl.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/dynamodb/dsl/DynamoDbDsl.java @@ -6,6 +6,7 @@ import java.math.BigDecimal; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -14,11 +15,18 @@ public final class DynamoDbDsl implements DynamoDbSequenceDsl, DynamoDbStatementDsl { private List insertions = new ArrayList<>(); + private final List previousInsertionDtos = new ArrayList<>(); private DynamoDbInsertionDto current; private DynamoDbDsl() { } + private DynamoDbDsl(List... previous) { + if (previous != null && previous.length > 0) { + Arrays.stream(previous).forEach(previousInsertionDtos::addAll); + } + } + /** * @return a new DynamoDB insertion sequence */ @@ -26,6 +34,15 @@ public static DynamoDbSequenceDsl dynamoDb() { return new DynamoDbDsl(); } + /** + * @param previous insertion sequences executed before this one + * @return a new DynamoDB insertion sequence + */ + @SafeVarargs + public static DynamoDbSequenceDsl dynamoDb(List... previous) { + return new DynamoDbDsl(previous); + } + @Override public DynamoDbStatementDsl insertInto(String tableName) { checkOpen(); diff --git a/client-java/controller/src/test/java/org/evomaster/client/java/controller/dynamodb/dsl/DynamoDbDslTest.java b/client-java/controller/src/test/java/org/evomaster/client/java/controller/dynamodb/dsl/DynamoDbDslTest.java index 6ad05b8bae..92d1d6f3c7 100644 --- a/client-java/controller/src/test/java/org/evomaster/client/java/controller/dynamodb/dsl/DynamoDbDslTest.java +++ b/client-java/controller/src/test/java/org/evomaster/client/java/controller/dynamodb/dsl/DynamoDbDslTest.java @@ -50,6 +50,22 @@ public void testDistinguishesQuotedWorldCupPlayerValues() { assertInsertion(insertion, "WorldCupPlayers", "captain", DynamoDbScalarTypeDto.BOOLEAN, "true"); } + @Test + public void testAcceptsPreviousWorldCupPlayerInsertions() { + List previous = DynamoDbDsl.dynamoDb() + .insertInto("WorldCupPlayers") + .d("country", "'Argentina'") + .dtos(); + + List current = DynamoDbDsl.dynamoDb(previous) + .insertInto("WorldCupPlayers") + .d("country", "'Brazil'") + .dtos(); + + assertEquals(1, current.size()); + assertInsertion(current.get(0), "WorldCupPlayers", "country", DynamoDbScalarTypeDto.STRING, "Brazil"); + } + @Test public void testRejectsIncompleteInsertionDefinitions() { assertThrows(IllegalArgumentException.class, () -> DynamoDbDsl.dynamoDb().insertInto(null)); diff --git a/core/src/main/kotlin/org/evomaster/core/output/DynamoDbWriter.kt b/core/src/main/kotlin/org/evomaster/core/output/DynamoDbWriter.kt new file mode 100644 index 0000000000..16e521f9a4 --- /dev/null +++ b/core/src/main/kotlin/org/evomaster/core/output/DynamoDbWriter.kt @@ -0,0 +1,67 @@ +package org.evomaster.core.output + +import org.apache.commons.text.StringEscapeUtils +import org.evomaster.client.java.controller.api.dto.database.operations.DynamoDbScalarTypeDto +import org.evomaster.core.search.action.EvaluatedDynamoDbAction +import org.evomaster.core.search.gene.BooleanGene +import org.evomaster.core.search.gene.numeric.BigDecimalGene +import org.evomaster.core.search.gene.string.StringGene + +/** Generates DynamoDB initialization code for emitted tests. */ +object DynamoDbWriter { + + /** + * Generates DynamoDB insert actions for a test case. + * + * @param format format of the generated test + * @param actions evaluated DynamoDB actions to generate + * @param lines destination for the generated code + * @param groupIndex suffix distinguishing this initialization group + * @param dynamoDbInsertionVars previous DynamoDB insertion variable names and their result variable names + * @param skipFailure whether failed insertions should be omitted + */ + fun handleDynamoDbInitialization( + format: OutputFormat, + actions: List, + lines: Lines, + groupIndex: String = "", + dynamoDbInsertionVars: MutableList>, + skipFailure: Boolean + ) { + val selected = actions.filter { !skipFailure || it.dynamoDbResult.getInsertExecutionResult() } + if (selected.isEmpty()) return + val insertionVar = "insertions_dynamodb${groupIndex}" + val resultVar = "${insertionVar}_result" + val previousVar = dynamoDbInsertionVars.joinToString(", ") { it.first } + lines.add(if (format.isJava()) "List $insertionVar = dynamoDb($previousVar)" else "val $insertionVar = dynamoDb($previousVar)") + lines.indent() + selected.forEach { evaluated -> + val action = evaluated.dynamoDbAction + lines.add(".insertInto(\"${escape(action.tableName, format)}\")") + action.attributes.forEach { attribute -> + val name = "\"${escape(attribute.attributeName, format)}\"" + val value = when (attribute.type) { + DynamoDbScalarTypeDto.STRING -> (attribute.gene as StringGene).getValueAsPrintableString(targetFormat = format) + DynamoDbScalarTypeDto.NUMBER -> "\"${(attribute.gene as BigDecimalGene).value.toPlainString()}\"" + DynamoDbScalarTypeDto.BOOLEAN -> (attribute.gene as BooleanGene).value.toString() + } + val method = when (attribute.type) { + DynamoDbScalarTypeDto.STRING -> "s" + DynamoDbScalarTypeDto.NUMBER -> "n" + DynamoDbScalarTypeDto.BOOLEAN -> "bool" + } + lines.add(".$method($name, $value)") + } + } + lines.add(".dtos()") + lines.appendSemicolon() + lines.deindent() + val declaration = if (format.isJava()) "DynamoDbInsertionResultsDto " else "val " + lines.add("${declaration}${resultVar} = controller.execInsertionsIntoDynamoDb($insertionVar)") + lines.appendSemicolon() + dynamoDbInsertionVars.add(insertionVar to resultVar) + } + + private fun escape(value: String, format: OutputFormat): String = + StringEscapeUtils.escapeJava(value).let { if (format.isKotlin()) it.replace("$", "\\$") else it } +} diff --git a/core/src/main/kotlin/org/evomaster/core/output/service/ApiTestCaseWriter.kt b/core/src/main/kotlin/org/evomaster/core/output/service/ApiTestCaseWriter.kt index db2b43d91c..80d79c2b40 100644 --- a/core/src/main/kotlin/org/evomaster/core/output/service/ApiTestCaseWriter.kt +++ b/core/src/main/kotlin/org/evomaster/core/output/service/ApiTestCaseWriter.kt @@ -9,10 +9,13 @@ import org.evomaster.core.output.* import org.evomaster.core.problem.externalservice.HostnameResolutionAction import org.evomaster.core.database.redis.RedisDbAction import org.evomaster.core.database.redis.RedisDbActionResult +import org.evomaster.core.database.dynamodb.DynamoDbAction +import org.evomaster.core.database.dynamodb.DynamoDbActionResult import org.evomaster.core.search.EvaluatedIndividual import org.evomaster.core.search.action.EvaluatedDbAction import org.evomaster.core.search.action.EvaluatedMongoDbAction import org.evomaster.core.search.action.EvaluatedRedisDbAction +import org.evomaster.core.search.action.EvaluatedDynamoDbAction import org.evomaster.core.search.gene.utils.GeneUtils import org.evomaster.core.database.sql.SqlAction import org.evomaster.core.database.sql.SqlActionResult @@ -50,6 +53,7 @@ abstract class ApiTestCaseWriter : TestCaseWriter() { sqlInsertionVars: MutableList>, mongoInsertionVars: MutableList>, redisInsertionVars: MutableList>, + dynamoDbInsertionVars: MutableList>, testName: String ) { @@ -69,6 +73,11 @@ abstract class ApiTestCaseWriter : TestCaseWriter() { if (initializingRedisResults.any { (it as? RedisDbActionResult) == null }) throw IllegalStateException("the type of results are expected as RedisDbActionResults") + val initializingDynamoDbActions = ind.individual.seeInitializingActions().filterIsInstance() + val initializingDynamoDbResults = ind.seeResults(initializingDynamoDbActions) + if (initializingDynamoDbResults.any { it !is DynamoDbActionResult }) + throw IllegalStateException("the type of results are expected as DynamoDbActionResults") + val initializingHostnameResolutionActions = ind.individual .seeInitializingActions() .filterIsInstance() @@ -107,6 +116,18 @@ abstract class ApiTestCaseWriter : TestCaseWriter() { // Same flag skipFailureSQLInTestFile as in mongo and sql. } + if (initializingDynamoDbActions.isNotEmpty()) { + DynamoDbWriter.handleDynamoDbInitialization( + format, + initializingDynamoDbActions.indices.map { + EvaluatedDynamoDbAction(initializingDynamoDbActions[it], initializingDynamoDbResults[it] as DynamoDbActionResult) + }, + lines, + dynamoDbInsertionVars = dynamoDbInsertionVars, + skipFailure = config.skipFailureSQLInTestFile + ) + } + if (initializingHostnameResolutionActions.isNotEmpty()) { handleHostnameResolutionActions(lines, initializingHostnameResolutionActions) } diff --git a/core/src/main/kotlin/org/evomaster/core/output/service/GraphQLTestCaseWriter.kt b/core/src/main/kotlin/org/evomaster/core/output/service/GraphQLTestCaseWriter.kt index 8b87bde0ba..a43ff62bba 100644 --- a/core/src/main/kotlin/org/evomaster/core/output/service/GraphQLTestCaseWriter.kt +++ b/core/src/main/kotlin/org/evomaster/core/output/service/GraphQLTestCaseWriter.kt @@ -32,6 +32,7 @@ class GraphQLTestCaseWriter : HttpWsTestCaseWriter() { sqlInsertionVars: MutableList>, mongoInsertionVars: MutableList>, redisInsertionVars: MutableList>, + dynamoDbInsertionVars: MutableList>, testCaseName: String, testSuitePath: Path?){ if (ind.individual is GraphQLIndividual) { diff --git a/core/src/main/kotlin/org/evomaster/core/output/service/HttpWsTestCaseWriter.kt b/core/src/main/kotlin/org/evomaster/core/output/service/HttpWsTestCaseWriter.kt index 70f6215f89..da5acdac86 100644 --- a/core/src/main/kotlin/org/evomaster/core/output/service/HttpWsTestCaseWriter.kt +++ b/core/src/main/kotlin/org/evomaster/core/output/service/HttpWsTestCaseWriter.kt @@ -97,6 +97,7 @@ abstract class HttpWsTestCaseWriter : ApiTestCaseWriter() { sqlInsertionVars: MutableList>, mongoInsertionVars: MutableList>, redisInsertionVars: MutableList>, + dynamoDbInsertionVars: MutableList>, testName: String ) { CookieWriter.handleGettingCookies(format, ind, lines, baseUrlOfSut, this) @@ -107,6 +108,7 @@ abstract class HttpWsTestCaseWriter : ApiTestCaseWriter() { sqlInsertionVars, mongoInsertionVars, redisInsertionVars, + dynamoDbInsertionVars, testName) } diff --git a/core/src/main/kotlin/org/evomaster/core/output/service/NoTestCaseWriter.kt b/core/src/main/kotlin/org/evomaster/core/output/service/NoTestCaseWriter.kt index 45fbe792fd..9cd976886f 100644 --- a/core/src/main/kotlin/org/evomaster/core/output/service/NoTestCaseWriter.kt +++ b/core/src/main/kotlin/org/evomaster/core/output/service/NoTestCaseWriter.kt @@ -15,12 +15,13 @@ class NoTestCaseWriter : TestCaseWriter() { sqlInsertionVars: MutableList>, mongoInsertionVars: MutableList>, redisInsertionVars: MutableList>, + dynamoDbInsertionVars: MutableList>, testName: String ) { // empty } - override fun handleActionCalls(lines: Lines, baseUrlOfSut: String, ind: EvaluatedIndividual<*>, sqlInsertionVars: MutableList>, mongoInsertionVars: MutableList>, redisInsertionVars: MutableList>, testCaseName: String, testSuitePath: Path?) { + override fun handleActionCalls(lines: Lines, baseUrlOfSut: String, ind: EvaluatedIndividual<*>, sqlInsertionVars: MutableList>, mongoInsertionVars: MutableList>, redisInsertionVars: MutableList>, dynamoDbInsertionVars: MutableList>, testCaseName: String, testSuitePath: Path?) { //empty } diff --git a/core/src/main/kotlin/org/evomaster/core/output/service/RPCTestCaseWriter.kt b/core/src/main/kotlin/org/evomaster/core/output/service/RPCTestCaseWriter.kt index ca9433a44f..a83491493d 100644 --- a/core/src/main/kotlin/org/evomaster/core/output/service/RPCTestCaseWriter.kt +++ b/core/src/main/kotlin/org/evomaster/core/output/service/RPCTestCaseWriter.kt @@ -59,6 +59,7 @@ class RPCTestCaseWriter : ApiTestCaseWriter() { sqlInsertionVars: MutableList>, mongoInsertionVars: MutableList>, redisInsertionVars: MutableList>, + dynamoDbInsertionVars: MutableList>, testName: String ) { super.handleTestInitialization(lines, @@ -67,6 +68,7 @@ class RPCTestCaseWriter : ApiTestCaseWriter() { sqlInsertionVars, mongoInsertionVars, redisInsertionVars, + dynamoDbInsertionVars, testName) @@ -85,6 +87,7 @@ class RPCTestCaseWriter : ApiTestCaseWriter() { sqlInsertionVars: MutableList>, mongoInsertionVars: MutableList>, redisInsertionVars: MutableList>, + dynamoDbInsertionVars: MutableList>, testCaseName: String, testSuitePath: Path? ) { diff --git a/core/src/main/kotlin/org/evomaster/core/output/service/RestTestCaseWriter.kt b/core/src/main/kotlin/org/evomaster/core/output/service/RestTestCaseWriter.kt index 28251bdd5f..160fb5f683 100644 --- a/core/src/main/kotlin/org/evomaster/core/output/service/RestTestCaseWriter.kt +++ b/core/src/main/kotlin/org/evomaster/core/output/service/RestTestCaseWriter.kt @@ -74,6 +74,7 @@ class RestTestCaseWriter : HttpWsTestCaseWriter { sqlInsertionVars: MutableList>, mongoInsertionVars: MutableList>, redisInsertionVars: MutableList>, + dynamoDbInsertionVars: MutableList>, testName: String ) { super.handleTestInitialization(lines, @@ -82,6 +83,7 @@ class RestTestCaseWriter : HttpWsTestCaseWriter { sqlInsertionVars, mongoInsertionVars, redisInsertionVars, + dynamoDbInsertionVars, testName) } @@ -92,6 +94,7 @@ class RestTestCaseWriter : HttpWsTestCaseWriter { sqlInsertionVars: MutableList>, mongoInsertionVars: MutableList>, redisInsertionVars: MutableList>, + dynamoDbInsertionVars: MutableList>, testCaseName: String, testSuitePath: Path? ) { diff --git a/core/src/main/kotlin/org/evomaster/core/output/service/TestCaseWriter.kt b/core/src/main/kotlin/org/evomaster/core/output/service/TestCaseWriter.kt index d0c1dae458..7ff07f095d 100644 --- a/core/src/main/kotlin/org/evomaster/core/output/service/TestCaseWriter.kt +++ b/core/src/main/kotlin/org/evomaster/core/output/service/TestCaseWriter.kt @@ -146,11 +146,12 @@ abstract class TestCaseWriter { val sqlInsertionVars = mutableListOf>() val mongoInsertionVars = mutableListOf>() val redisInsertionVars = mutableListOf>() + val dynamoDbInsertionVars = mutableListOf>() // FIXME: HostnameResolutionActions can be a separately, for now it's under // handleFieldDeclarations. - handleTestInitialization(lines, baseUrlOfSut, ind, sqlInsertionVars, mongoInsertionVars, redisInsertionVars, test.name) - handleActionCalls(lines, baseUrlOfSut, ind, sqlInsertionVars, mongoInsertionVars, redisInsertionVars, testCaseName = test.name, testSuitePath) - handleCleanUpActions(lines, baseUrlOfSut, ind, sqlInsertionVars, mongoInsertionVars, redisInsertionVars, test.name,testSuitePath) + handleTestInitialization(lines, baseUrlOfSut, ind, sqlInsertionVars, mongoInsertionVars, redisInsertionVars, dynamoDbInsertionVars, test.name) + handleActionCalls(lines, baseUrlOfSut, ind, sqlInsertionVars, mongoInsertionVars, redisInsertionVars, dynamoDbInsertionVars, testCaseName = test.name, testSuitePath) + handleCleanUpActions(lines, baseUrlOfSut, ind, sqlInsertionVars, mongoInsertionVars, redisInsertionVars, dynamoDbInsertionVars, test.name,testSuitePath) } @@ -223,6 +224,7 @@ abstract class TestCaseWriter { * @param sqlInsertionVars contains variable names of sql insertions (Pair.first) with their results (Pair.second). * @param mongoInsertionVars contains variable names of mongo insertions (Pair.first) with their results (Pair.second). * @param redisInsertionVars contains variable names of redis insertions (Pair.first) with their results (Pair.second). + * @param dynamoDbInsertionVars contains variable names of DynamoDB insertions (Pair.first) with their results (Pair.second). */ protected abstract fun handleTestInitialization( lines: Lines, @@ -231,6 +233,7 @@ abstract class TestCaseWriter { sqlInsertionVars: MutableList>, mongoInsertionVars: MutableList>, redisInsertionVars: MutableList>, + dynamoDbInsertionVars: MutableList>, testName: String ) @@ -242,6 +245,7 @@ abstract class TestCaseWriter { * @param sqlInsertionVars contains variable names of sql insertions (Pair.first) with their results (Pair.second). * @param mongoInsertionVars contains variable names of mongo insertions (Pair.first) with their results (Pair.second). * @param redisInsertionVars contains variable names of redis insertions (Pair.first) with their results (Pair.second). + * @param dynamoDbInsertionVars contains variable names of DynamoDB insertions (Pair.first) with their results (Pair.second). */ protected abstract fun handleActionCalls( lines: Lines, @@ -250,6 +254,7 @@ abstract class TestCaseWriter { sqlInsertionVars: MutableList>, mongoInsertionVars: MutableList>, redisInsertionVars: MutableList>, + dynamoDbInsertionVars: MutableList>, testCaseName: String, testSuitePath: Path? ) @@ -261,6 +266,7 @@ abstract class TestCaseWriter { sqlInsertionVars: MutableList>, mongoInsertionVars: MutableList>, redisInsertionVars: MutableList>, + dynamoDbInsertionVars: MutableList>, testCaseName: String, testSuitePath: Path? ){ diff --git a/core/src/main/kotlin/org/evomaster/core/output/service/TestSuiteWriter.kt b/core/src/main/kotlin/org/evomaster/core/output/service/TestSuiteWriter.kt index 7840ee8f5e..2669f171b4 100644 --- a/core/src/main/kotlin/org/evomaster/core/output/service/TestSuiteWriter.kt +++ b/core/src/main/kotlin/org/evomaster/core/output/service/TestSuiteWriter.kt @@ -4,6 +4,7 @@ import com.google.inject.Inject import org.evomaster.client.java.controller.api.dto.database.operations.InsertionDto import org.evomaster.client.java.controller.api.dto.database.operations.MongoInsertionDto import org.evomaster.client.java.controller.api.dto.database.operations.RedisInsertionDto +import org.evomaster.client.java.controller.api.dto.database.operations.DynamoDbInsertionDto import org.evomaster.client.java.instrumentation.shared.ExternalServiceSharedUtils import org.evomaster.core.EMConfig import org.evomaster.core.output.* @@ -510,6 +511,12 @@ class TestSuiteWriter { addImport(RedisInsertionDto::class.qualifiedName!!, lines) } + if (solution.hasAnyDynamoDbAction()) { + addImport("org.evomaster.client.java.controller.dynamodb.dsl.DynamoDbDsl.dynamoDb", lines, true) + addImport("org.evomaster.client.java.controller.api.dto.database.operations.DynamoDbInsertionResultsDto", lines) + addImport(DynamoDbInsertionDto::class.qualifiedName!!, lines) + } + if (useRestAssured()) { addImport("io.restassured.config.JsonConfig", lines) addImport("io.restassured.path.json.config.JsonPathConfig", lines) diff --git a/core/src/main/kotlin/org/evomaster/core/output/service/WebTestCaseWriter.kt b/core/src/main/kotlin/org/evomaster/core/output/service/WebTestCaseWriter.kt index b8aa281fcf..473804b78e 100644 --- a/core/src/main/kotlin/org/evomaster/core/output/service/WebTestCaseWriter.kt +++ b/core/src/main/kotlin/org/evomaster/core/output/service/WebTestCaseWriter.kt @@ -20,6 +20,7 @@ class WebTestCaseWriter : TestCaseWriter() { sqlInsertionVars: MutableList>, mongoInsertionVars: MutableList>, redisInsertionVars: MutableList>, + dynamoDbInsertionVars: MutableList>, testName: String ) { //nothing to do? at least for now... @@ -32,6 +33,7 @@ class WebTestCaseWriter : TestCaseWriter() { sqlInsertionVars: MutableList>, mongoInsertionVars: MutableList>, redisInsertionVars: MutableList>, + dynamoDbInsertionVars: MutableList>, testCaseName: String, testSuitePath: Path? ) { diff --git a/core/src/main/kotlin/org/evomaster/core/search/Solution.kt b/core/src/main/kotlin/org/evomaster/core/search/Solution.kt index 21a1ac5150..f1af26ccc9 100644 --- a/core/src/main/kotlin/org/evomaster/core/search/Solution.kt +++ b/core/src/main/kotlin/org/evomaster/core/search/Solution.kt @@ -9,6 +9,7 @@ import org.evomaster.core.output.TestSuiteFileName import org.evomaster.core.problem.enterprise.DetectedFaultUtils import org.evomaster.core.problem.externalservice.HostnameResolutionAction import org.evomaster.core.database.redis.RedisDbAction +import org.evomaster.core.database.dynamodb.DynamoDbAction class Solution( @@ -87,6 +88,10 @@ where T : Individual { return individuals.any { ind -> ind.individual.seeAllActions().any { a -> a is RedisDbAction}} } + fun hasAnyDynamoDbAction() : Boolean{ + return individuals.any { ind -> ind.individual.seeAllActions().any { a -> a is DynamoDbAction } } + } + /** * extract individual generated during seeding as a solution */ diff --git a/core/src/main/kotlin/org/evomaster/core/search/action/EvaluatedAction.kt b/core/src/main/kotlin/org/evomaster/core/search/action/EvaluatedAction.kt index 7bda63b2ba..c6f4f6e900 100644 --- a/core/src/main/kotlin/org/evomaster/core/search/action/EvaluatedAction.kt +++ b/core/src/main/kotlin/org/evomaster/core/search/action/EvaluatedAction.kt @@ -6,6 +6,8 @@ import org.evomaster.core.database.mongo.MongoDbAction import org.evomaster.core.database.mongo.MongoDbActionResult import org.evomaster.core.database.redis.RedisDbAction import org.evomaster.core.database.redis.RedisDbActionResult +import org.evomaster.core.database.dynamodb.DynamoDbAction +import org.evomaster.core.database.dynamodb.DynamoDbActionResult open class EvaluatedAction(val action: Action, val result: ActionResult){ @@ -25,4 +27,6 @@ class EvaluatedDbAction(val sqlAction: SqlAction, val sqlResult: SqlActionResult class EvaluatedMongoDbAction(val mongoAction: MongoDbAction, val mongoResult: MongoDbActionResult) : EvaluatedAction(mongoAction, mongoResult) -class EvaluatedRedisDbAction(val redisAction: RedisDbAction, val redisResult: RedisDbActionResult) : EvaluatedAction(redisAction, redisResult) \ No newline at end of file +class EvaluatedRedisDbAction(val redisAction: RedisDbAction, val redisResult: RedisDbActionResult) : EvaluatedAction(redisAction, redisResult) + +class EvaluatedDynamoDbAction(val dynamoDbAction: DynamoDbAction, val dynamoDbResult: DynamoDbActionResult) : EvaluatedAction(dynamoDbAction, dynamoDbResult) diff --git a/core/src/test/kotlin/org/evomaster/core/output/DynamoDbWriterTest.kt b/core/src/test/kotlin/org/evomaster/core/output/DynamoDbWriterTest.kt new file mode 100644 index 0000000000..669e482b34 --- /dev/null +++ b/core/src/test/kotlin/org/evomaster/core/output/DynamoDbWriterTest.kt @@ -0,0 +1,103 @@ +package org.evomaster.core.output + +import org.evomaster.client.java.controller.api.dto.database.operations.DynamoDbScalarTypeDto +import org.evomaster.core.database.dynamodb.DynamoDbAction +import org.evomaster.core.database.dynamodb.DynamoDbActionResult +import org.evomaster.core.database.dynamodb.DynamoDbAttributeGene +import org.evomaster.core.search.action.EvaluatedDynamoDbAction +import org.evomaster.core.search.gene.string.StringGene +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test + +/** Tests generated DynamoDB initialization code. */ +class DynamoDbWriterTest { + + /** Creates an evaluated insertion for an Argentinian World Cup player. */ + private fun evaluatedWorldCupPlayer(): EvaluatedDynamoDbAction { + val action = DynamoDbAction( + "WorldCupPlayers", + listOf( + DynamoDbAttributeGene( + "country", + DynamoDbScalarTypeDto.STRING, + StringGene("country", "Argentina") + ) + ) + ) + action.setLocalId("world-cup-player-insertion") + val result = DynamoDbActionResult(action.getLocalId()).also { + it.setInsertExecutionResult(true) + } + return EvaluatedDynamoDbAction(action, result) + } + + @Test + fun groupIndexDistinguishesGeneratedVariables() { + val lines = Lines(OutputFormat.KOTLIN_JUNIT_5) + + DynamoDbWriter.handleDynamoDbInitialization( + format = OutputFormat.KOTLIN_JUNIT_5, + actions = listOf(evaluatedWorldCupPlayer()), + lines = lines, + groupIndex = "_2", + dynamoDbInsertionVars = mutableListOf(), + skipFailure = false + ) + + val output = lines.toString() + assertTrue(output.contains("val insertions_dynamodb_2 = dynamoDb()")) + assertTrue( + output.contains( + "val insertions_dynamodb_2_result = " + + "controller.execInsertionsIntoDynamoDb(insertions_dynamodb_2)" + ) + ) + } + + @Test + fun defaultGroupIndexPreservesGeneratedVariables() { + val lines = Lines(OutputFormat.KOTLIN_JUNIT_5) + + DynamoDbWriter.handleDynamoDbInitialization( + format = OutputFormat.KOTLIN_JUNIT_5, + actions = listOf(evaluatedWorldCupPlayer()), + lines = lines, + dynamoDbInsertionVars = mutableListOf(), + skipFailure = false + ) + + val output = lines.toString() + assertTrue(output.contains("val insertions_dynamodb = dynamoDb()")) + assertTrue( + output.contains( + "val insertions_dynamodb_result = " + + "controller.execInsertionsIntoDynamoDb(insertions_dynamodb)" + ) + ) + } + + @Test + fun previousInsertionVariablesAreTracked() { + val lines = Lines(OutputFormat.KOTLIN_JUNIT_5) + val insertionVars = mutableListOf("insertions_dynamodb_1" to "insertions_dynamodb_1_result") + + DynamoDbWriter.handleDynamoDbInitialization( + format = OutputFormat.KOTLIN_JUNIT_5, + actions = listOf(evaluatedWorldCupPlayer()), + lines = lines, + groupIndex = "_2", + dynamoDbInsertionVars = insertionVars, + skipFailure = false + ) + + assertTrue(lines.toString().contains("val insertions_dynamodb_2 = dynamoDb(insertions_dynamodb_1)")) + assertEquals( + listOf( + "insertions_dynamodb_1" to "insertions_dynamodb_1_result", + "insertions_dynamodb_2" to "insertions_dynamodb_2_result" + ), + insertionVars + ) + } +}