Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
Expand All @@ -14,18 +15,34 @@
public final class DynamoDbDsl implements DynamoDbSequenceDsl, DynamoDbStatementDsl {

private List<DynamoDbInsertionDto> insertions = new ArrayList<>();
private final List<DynamoDbInsertionDto> previousInsertionDtos = new ArrayList<>();
private DynamoDbInsertionDto current;

private DynamoDbDsl() {
}

private DynamoDbDsl(List<DynamoDbInsertionDto>... previous) {
if (previous != null && previous.length > 0) {
Arrays.stream(previous).forEach(previousInsertionDtos::addAll);
}
}

/**
* @return a new DynamoDB insertion sequence
*/
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<DynamoDbInsertionDto>... previous) {
return new DynamoDbDsl(previous);
}

@Override
public DynamoDbStatementDsl insertInto(String tableName) {
checkOpen();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,22 @@ public void testDistinguishesQuotedWorldCupPlayerValues() {
assertInsertion(insertion, "WorldCupPlayers", "captain", DynamoDbScalarTypeDto.BOOLEAN, "true");
}

@Test
public void testAcceptsPreviousWorldCupPlayerInsertions() {
List<DynamoDbInsertionDto> previous = DynamoDbDsl.dynamoDb()
.insertInto("WorldCupPlayers")
.d("country", "'Argentina'")
.dtos();

List<DynamoDbInsertionDto> 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));
Expand Down
67 changes: 67 additions & 0 deletions core/src/main/kotlin/org/evomaster/core/output/DynamoDbWriter.kt
Original file line number Diff line number Diff line change
@@ -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<EvaluatedDynamoDbAction>,
lines: Lines,
groupIndex: String = "",
dynamoDbInsertionVars: MutableList<Pair<String, String>>,
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<DynamoDbInsertionDto> $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 }
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -50,6 +53,7 @@ abstract class ApiTestCaseWriter : TestCaseWriter() {
sqlInsertionVars: MutableList<Pair<String, String>>,
mongoInsertionVars: MutableList<Pair<String, String>>,
redisInsertionVars: MutableList<Pair<String, String>>,
dynamoDbInsertionVars: MutableList<Pair<String, String>>,
testName: String
) {

Expand All @@ -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<DynamoDbAction>()
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<HostnameResolutionAction>()
Expand Down Expand Up @@ -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)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class GraphQLTestCaseWriter : HttpWsTestCaseWriter() {
sqlInsertionVars: MutableList<Pair<String, String>>,
mongoInsertionVars: MutableList<Pair<String, String>>,
redisInsertionVars: MutableList<Pair<String, String>>,
dynamoDbInsertionVars: MutableList<Pair<String, String>>,
testCaseName: String, testSuitePath: Path?){

if (ind.individual is GraphQLIndividual) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ abstract class HttpWsTestCaseWriter : ApiTestCaseWriter() {
sqlInsertionVars: MutableList<Pair<String, String>>,
mongoInsertionVars: MutableList<Pair<String, String>>,
redisInsertionVars: MutableList<Pair<String, String>>,
dynamoDbInsertionVars: MutableList<Pair<String, String>>,
testName: String
) {
CookieWriter.handleGettingCookies(format, ind, lines, baseUrlOfSut, this)
Expand All @@ -107,6 +108,7 @@ abstract class HttpWsTestCaseWriter : ApiTestCaseWriter() {
sqlInsertionVars,
mongoInsertionVars,
redisInsertionVars,
dynamoDbInsertionVars,
testName)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ class NoTestCaseWriter : TestCaseWriter() {
sqlInsertionVars: MutableList<Pair<String, String>>,
mongoInsertionVars: MutableList<Pair<String, String>>,
redisInsertionVars: MutableList<Pair<String, String>>,
dynamoDbInsertionVars: MutableList<Pair<String, String>>,
testName: String
) {
// empty
}

override fun handleActionCalls(lines: Lines, baseUrlOfSut: String, ind: EvaluatedIndividual<*>, sqlInsertionVars: MutableList<Pair<String, String>>, mongoInsertionVars: MutableList<Pair<String, String>>, redisInsertionVars: MutableList<Pair<String, String>>, testCaseName: String, testSuitePath: Path?) {
override fun handleActionCalls(lines: Lines, baseUrlOfSut: String, ind: EvaluatedIndividual<*>, sqlInsertionVars: MutableList<Pair<String, String>>, mongoInsertionVars: MutableList<Pair<String, String>>, redisInsertionVars: MutableList<Pair<String, String>>, dynamoDbInsertionVars: MutableList<Pair<String, String>>, testCaseName: String, testSuitePath: Path?) {
//empty
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class RPCTestCaseWriter : ApiTestCaseWriter() {
sqlInsertionVars: MutableList<Pair<String, String>>,
mongoInsertionVars: MutableList<Pair<String, String>>,
redisInsertionVars: MutableList<Pair<String, String>>,
dynamoDbInsertionVars: MutableList<Pair<String, String>>,
testName: String
) {
super.handleTestInitialization(lines,
Expand All @@ -67,6 +68,7 @@ class RPCTestCaseWriter : ApiTestCaseWriter() {
sqlInsertionVars,
mongoInsertionVars,
redisInsertionVars,
dynamoDbInsertionVars,
testName)


Expand All @@ -85,6 +87,7 @@ class RPCTestCaseWriter : ApiTestCaseWriter() {
sqlInsertionVars: MutableList<Pair<String, String>>,
mongoInsertionVars: MutableList<Pair<String, String>>,
redisInsertionVars: MutableList<Pair<String, String>>,
dynamoDbInsertionVars: MutableList<Pair<String, String>>,
testCaseName: String,
testSuitePath: Path?
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class RestTestCaseWriter : HttpWsTestCaseWriter {
sqlInsertionVars: MutableList<Pair<String, String>>,
mongoInsertionVars: MutableList<Pair<String, String>>,
redisInsertionVars: MutableList<Pair<String, String>>,
dynamoDbInsertionVars: MutableList<Pair<String, String>>,
testName: String
) {
super.handleTestInitialization(lines,
Expand All @@ -82,6 +83,7 @@ class RestTestCaseWriter : HttpWsTestCaseWriter {
sqlInsertionVars,
mongoInsertionVars,
redisInsertionVars,
dynamoDbInsertionVars,
testName)
}

Expand All @@ -92,6 +94,7 @@ class RestTestCaseWriter : HttpWsTestCaseWriter {
sqlInsertionVars: MutableList<Pair<String, String>>,
mongoInsertionVars: MutableList<Pair<String, String>>,
redisInsertionVars: MutableList<Pair<String, String>>,
dynamoDbInsertionVars: MutableList<Pair<String, String>>,
testCaseName: String,
testSuitePath: Path?
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,12 @@ abstract class TestCaseWriter {
val sqlInsertionVars = mutableListOf<Pair<String, String>>()
val mongoInsertionVars = mutableListOf<Pair<String, String>>()
val redisInsertionVars = mutableListOf<Pair<String, String>>()
val dynamoDbInsertionVars = mutableListOf<Pair<String, String>>()
// 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)
}


Expand Down Expand Up @@ -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,
Expand All @@ -231,6 +233,7 @@ abstract class TestCaseWriter {
sqlInsertionVars: MutableList<Pair<String, String>>,
mongoInsertionVars: MutableList<Pair<String, String>>,
redisInsertionVars: MutableList<Pair<String, String>>,
dynamoDbInsertionVars: MutableList<Pair<String, String>>,
testName: String
)

Expand All @@ -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,
Expand All @@ -250,6 +254,7 @@ abstract class TestCaseWriter {
sqlInsertionVars: MutableList<Pair<String, String>>,
mongoInsertionVars: MutableList<Pair<String, String>>,
redisInsertionVars: MutableList<Pair<String, String>>,
dynamoDbInsertionVars: MutableList<Pair<String, String>>,
testCaseName: String,
testSuitePath: Path?
)
Expand All @@ -261,6 +266,7 @@ abstract class TestCaseWriter {
sqlInsertionVars: MutableList<Pair<String, String>>,
mongoInsertionVars: MutableList<Pair<String, String>>,
redisInsertionVars: MutableList<Pair<String, String>>,
dynamoDbInsertionVars: MutableList<Pair<String, String>>,
testCaseName: String,
testSuitePath: Path?
){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.*
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class WebTestCaseWriter : TestCaseWriter() {
sqlInsertionVars: MutableList<Pair<String, String>>,
mongoInsertionVars: MutableList<Pair<String, String>>,
redisInsertionVars: MutableList<Pair<String, String>>,
dynamoDbInsertionVars: MutableList<Pair<String, String>>,
testName: String
) {
//nothing to do? at least for now...
Expand All @@ -32,6 +33,7 @@ class WebTestCaseWriter : TestCaseWriter() {
sqlInsertionVars: MutableList<Pair<String, String>>,
mongoInsertionVars: MutableList<Pair<String, String>>,
redisInsertionVars: MutableList<Pair<String, String>>,
dynamoDbInsertionVars: MutableList<Pair<String, String>>,
testCaseName: String,
testSuitePath: Path?
) {
Expand Down
5 changes: 5 additions & 0 deletions core/src/main/kotlin/org/evomaster/core/search/Solution.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>(
Expand Down Expand Up @@ -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
*/
Expand Down
Loading
Loading