Skip to content
Merged
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
@@ -0,0 +1,15 @@
package org.evomaster.client.java.controller.api.dto.database.execution;

import java.util.ArrayList;
import java.util.List;

/**
* DynamoDB reads that can be satisfied by generated initialization data.
*/
public class DynamoDbExecutionsDto {

public List<DynamoDbFailedQuery> failedQueries = new ArrayList<>();

public DynamoDbExecutionsDto() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.evomaster.client.java.controller.api.dto.database.execution;

import org.evomaster.client.java.controller.api.dto.database.operations.DynamoDbAttributeValueDto;

import java.util.ArrayList;
import java.util.List;

/**
* Equality constraints from a successful DynamoDB read that returned no matching item.
*/
public class DynamoDbFailedQuery {

public String tableName;
public List<DynamoDbAttributeValueDto> attributes = new ArrayList<>();

public DynamoDbFailedQuery() {
}

/**
* Creates a failed-query description.
*
* @param tableName target table
* @param attributes equality-constrained attributes
*/
public DynamoDbFailedQuery(String tableName, List<DynamoDbAttributeValueDto> attributes) {
this.tableName = tableName;
this.attributes = new ArrayList<>(attributes);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.evomaster.client.java.controller.api.dto.database.operations;

/**
* A named scalar DynamoDB attribute value.
*/
public class DynamoDbAttributeValueDto {

public String attributeName;
public DynamoDbScalarTypeDto type;
public String value;

public DynamoDbAttributeValueDto() {
}

/**
* Creates an attribute value.
*
* @param attributeName attribute name
* @param type DynamoDB scalar type
* @param value string-preserved value
*/
public DynamoDbAttributeValueDto(String attributeName, DynamoDbScalarTypeDto type, String value) {
this.attributeName = attributeName;
this.type = type;
this.value = value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.evomaster.client.java.controller.api.dto.database.operations;

import java.util.ArrayList;
import java.util.List;

/**
* DynamoDB insertion commands sent to the controller.
*/
public class DynamoDbDatabaseCommandsDto {

public List<DynamoDbInsertionDto> insertions = new ArrayList<>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.evomaster.client.java.controller.api.dto.database.operations;

import java.util.ArrayList;
import java.util.List;

/**
* An item to insert into a DynamoDB table.
*/
public class DynamoDbInsertionDto {

public String tableName;
public List<DynamoDbAttributeValueDto> attributes = new ArrayList<>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.evomaster.client.java.controller.api.dto.database.operations;

import java.util.ArrayList;
import java.util.List;

/**
* Results of a sequence of DynamoDB insertions.
*/
public class DynamoDbInsertionResultsDto {

public List<Boolean> executionResults = new ArrayList<>();
public Integer failedInsertionIndex;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.evomaster.client.java.controller.api.dto.database.operations;

/**
* Scalar DynamoDB attribute types supported by generated insertions.
*/
public enum DynamoDbScalarTypeDto {
STRING,
NUMBER,
BOOLEAN
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package org.evomaster.client.java.controller.dynamodb.dsl;

import org.evomaster.client.java.controller.api.dto.database.operations.DynamoDbAttributeValueDto;
import org.evomaster.client.java.controller.api.dto.database.operations.DynamoDbInsertionDto;
import org.evomaster.client.java.controller.api.dto.database.operations.DynamoDbScalarTypeDto;

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

/**
* DSL for DynamoDB insertions in generated tests.
*/
public final class DynamoDbDsl implements DynamoDbSequenceDsl, DynamoDbStatementDsl {

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

private DynamoDbDsl() {
}

/**
* @return a new DynamoDB insertion sequence
*/
public static DynamoDbSequenceDsl dynamoDb() {
return new DynamoDbDsl();
}

@Override
public DynamoDbStatementDsl insertInto(String tableName) {
checkOpen();
if (tableName == null || tableName.isEmpty()) {
throw new IllegalArgumentException("Unspecified table");
}
current = new DynamoDbInsertionDto();
current.tableName = tableName;
insertions.add(current);
return this;
}

@Override
public DynamoDbStatementDsl d(String attributeName, String printableValue) {
if (printableValue == null) {
throw new IllegalArgumentException("Unspecified attribute value");
}
if (isStringLiteral(printableValue)) {
String value = printableValue.substring(1, printableValue.length() - 1).replace("''", "'");
return attribute(attributeName, DynamoDbScalarTypeDto.STRING, value);
}
if ("true".equalsIgnoreCase(printableValue) || "false".equalsIgnoreCase(printableValue)) {
return attribute(attributeName, DynamoDbScalarTypeDto.BOOLEAN,
Boolean.toString(Boolean.parseBoolean(printableValue)));
}
try {
new BigDecimal(printableValue);
return attribute(attributeName, DynamoDbScalarTypeDto.NUMBER, printableValue);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Unsupported DynamoDB scalar value: " + printableValue, e);
}
}

@Override
public List<DynamoDbInsertionDto> dtos() {
checkOpen();
List<DynamoDbInsertionDto> result = insertions;
insertions = null;
current = null;
return result;
}

private DynamoDbStatementDsl attribute(String name, DynamoDbScalarTypeDto type, String value) {
checkOpen();
if (current == null) {
throw new IllegalStateException("Call insertInto before adding attributes");
}
if (name == null || name.isEmpty()) {
throw new IllegalArgumentException("Unspecified attribute name");
}
current.attributes.add(new DynamoDbAttributeValueDto(name, type, value));
return this;
}

/**
* @param value value to inspect
* @return whether the value is enclosed in single quotes
*/
private boolean isStringLiteral(String value) {
return value.length() >= 2 && value.charAt(0) == '\'' && value.charAt(value.length() - 1) == '\'';
}

private void checkOpen() {
if (insertions == null) {
throw new IllegalStateException("DTO was already built for this object");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.evomaster.client.java.controller.dynamodb.dsl;

/**
* Entry point for a DynamoDB insertion sequence.
*/
public interface DynamoDbSequenceDsl {

/**
* Starts an item insertion.
*
* @param tableName target table
* @return item statement
*/
DynamoDbStatementDsl insertInto(String tableName);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.evomaster.client.java.controller.dynamodb.dsl;

import org.evomaster.client.java.controller.api.dto.database.operations.DynamoDbInsertionDto;

import java.util.List;

/**
* Fluent definition of one DynamoDB item.
*/
public interface DynamoDbStatementDsl extends DynamoDbSequenceDsl {

/**
* Adds a scalar attribute using its printable representation. Strings must be enclosed in single quotes,
* numbers are represented by their exact text, and booleans are represented by {@code true} or {@code false}.
*
* @param attributeName attribute name
* @param printableValue scalar value in printable form
* @return the continuation of this statement
*/
DynamoDbStatementDsl d(String attributeName, String printableValue);

/** @return the completed insertion DTOs */
List<DynamoDbInsertionDto> dtos();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package org.evomaster.client.java.controller.dynamodb.dsl;

import org.evomaster.client.java.controller.api.dto.database.operations.DynamoDbAttributeValueDto;
import org.evomaster.client.java.controller.api.dto.database.operations.DynamoDbInsertionDto;
import org.evomaster.client.java.controller.api.dto.database.operations.DynamoDbScalarTypeDto;
import org.junit.jupiter.api.Test;

import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

/** Tests the DynamoDB insertion DTOs produced by the generated-test DSL. */
public class DynamoDbDslTest {

@Test
public void testBuildsWorldCupPlayerInsertions() {
List<DynamoDbInsertionDto> insertions = DynamoDbDsl.dynamoDb()
.insertInto("WorldCupPlayers")
.d("country", "'Argentina'")
.d("fifaId", "10")
.d("captain", "true")
.insertInto("WorldCupPlayers")
.d("country", "'Brazil'")
.d("fifaId", "1")
.dtos();

assertEquals(2, insertions.size());
assertInsertion(insertions.get(0), "WorldCupPlayers", "country", DynamoDbScalarTypeDto.STRING, "Argentina");
assertInsertion(insertions.get(0), "WorldCupPlayers", "fifaId", DynamoDbScalarTypeDto.NUMBER, "10");
assertInsertion(insertions.get(0), "WorldCupPlayers", "captain", DynamoDbScalarTypeDto.BOOLEAN, "true");
assertInsertion(insertions.get(1), "WorldCupPlayers", "country", DynamoDbScalarTypeDto.STRING, "Brazil");
assertInsertion(insertions.get(1), "WorldCupPlayers", "fifaId", DynamoDbScalarTypeDto.NUMBER, "1");
}

@Test
public void testDistinguishesQuotedWorldCupPlayerValues() {
DynamoDbInsertionDto insertion = DynamoDbDsl.dynamoDb()
.insertInto("WorldCupPlayers")
.d("shirtNumber", "'10'")
.d("captainLabel", "'true'")
.d("goals", "3e1")
.d("captain", "TRUE")
.dtos()
.get(0);

assertInsertion(insertion, "WorldCupPlayers", "shirtNumber", DynamoDbScalarTypeDto.STRING, "10");
assertInsertion(insertion, "WorldCupPlayers", "captainLabel", DynamoDbScalarTypeDto.STRING, "true");
assertInsertion(insertion, "WorldCupPlayers", "goals", DynamoDbScalarTypeDto.NUMBER, "3e1");
assertInsertion(insertion, "WorldCupPlayers", "captain", DynamoDbScalarTypeDto.BOOLEAN, "true");
}

@Test
public void testRejectsIncompleteInsertionDefinitions() {
assertThrows(IllegalArgumentException.class, () -> DynamoDbDsl.dynamoDb().insertInto(null));
assertThrows(IllegalArgumentException.class, () -> DynamoDbDsl.dynamoDb().insertInto(""));

DynamoDbStatementDsl statement = (DynamoDbStatementDsl) DynamoDbDsl.dynamoDb();
assertThrows(IllegalStateException.class, () -> statement.d("country", "'Argentina'"));

assertThrows(IllegalArgumentException.class, () -> DynamoDbDsl.dynamoDb()
.insertInto("WorldCupPlayers").d("country", null));
assertThrows(IllegalArgumentException.class, () -> DynamoDbDsl.dynamoDb()
.insertInto("WorldCupPlayers").d("country", "Argentina"));

DynamoDbStatementDsl completed = DynamoDbDsl.dynamoDb().insertInto("WorldCupPlayers");
completed.dtos();
assertThrows(IllegalStateException.class, () -> completed.insertInto("WorldCupPlayers"));
}

private void assertInsertion(
DynamoDbInsertionDto insertion,
String tableName,
String attributeName,
DynamoDbScalarTypeDto type,
String value) {
assertEquals(tableName, insertion.tableName);
DynamoDbAttributeValueDto attribute = insertion.attributes.stream()
.filter(candidate -> attributeName.equals(candidate.attributeName))
.findFirst()
.orElseThrow(() -> new AssertionError("Missing attribute " + attributeName));
assertEquals(type, attribute.type);
assertEquals(value, attribute.value);
}
}
Loading