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
Expand Up @@ -29,7 +29,7 @@ public void testRunEM(boolean heuristicsForSQLAdvanced) throws Throwable {
runTestHandlingFlakyAndCompilation(
"ResourceEM",
"org.db.resource.ResourceEM" + (heuristicsForSQLAdvanced ? "Complete" : "Partial"),
1_000,
2_000,
true,
(args) -> {
// disable taint analysis
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class SecurityExistenceLeakageNoExistenceEMTest : SpringTestBase(){

runTestHandlingFlakyAndCompilation(
"SecurityExistenceLeakageNoExistenceEM",
6000
10_000
) { args: MutableList<String> ->

setOption(args, "security", "true")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
import org.evomaster.core.problem.rest.data.HttpVerb;
import org.evomaster.core.problem.rest.data.RestIndividual;
import org.evomaster.core.search.Solution;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertTrue;

//FIXME failing due EnumGeneImpact.countImpactWithMutatedGeneWithContext
@Disabled
public class HLEMTest extends HLTestBase {


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public void testRunEM(boolean heuristicsForSQLAdvanced) throws Throwable {
runTestHandlingFlakyAndCompilation(
"ResourceDBEM",
"org.db.resource.ResourceEM" + (heuristicsForSQLAdvanced ? "Complete" : "Partial"),
1_000,
2_000,
true,
(args) -> {
// disable taint analysis
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,11 +336,16 @@ abstract class EnterpriseIndividual(
val relatedActionInMain = seeFixedMainActions()
.flatMap { it.flatten() }
.filterIsInstance<SqlAction>()

//first try to repair considering all actions... but side effects on removal will be ignored
SqlActionUtils.repairBrokenDbActionsList(
previous.plus(relatedActionInMain).toMutableList(),
randomness
)
SqlActionUtils.repairBrokenDbActionsList(previous, randomness)
//needed if actions were removed in the list "previous"
resetInitializingActions(previous)

Lazy.assert{verifyInitializationActions()}
}
}
Expand Down Expand Up @@ -391,7 +396,9 @@ abstract class EnterpriseIndividual(
" ${invalid.map { it::class.java.simpleName }.toSet().joinToString(", ")}")
}

addInitializingDbActions(actions = actions.filterIsInstance<SqlAction>())
var skipped = 0

skipped += addInitializingDbActions(actions = actions.filterIsInstance<SqlAction>())
addInitializingMongoDbActions(actions = actions.filterIsInstance<MongoDbAction>())
addInitializingScheduleTaskActions(actions = actions.filterIsInstance<ScheduleTaskAction>())

Expand All @@ -403,24 +410,40 @@ abstract class EnterpriseIndividual(

addInitializingHostnameResolutionActions(actions = uniqueHostnames)

return hostnameActions.size - uniqueHostnames.size
skipped += hostnameActions.size - uniqueHostnames.size

return skipped
}


/**
* add [actions] at [relativePosition]
* if [relativePosition] = -1, append the [actions] at the end
*/
fun addInitializingDbActions(relativePosition: Int=-1, actions: List<Action>){
fun addInitializingDbActions(relativePosition: Int=-1, actions: List<Action>) : Int{

var skipped = 0

/*
SQL actions representing existing data must ALWAYS be at the beginning.
Recall those are only used for FKs.
*/
val (existing, others) = actions.partition { it is SqlAction && it.representExistingData }
val (existing, others) = actions.filterIsInstance<SqlAction>()
.partition { it.representExistingData }

if(existing.isNotEmpty()){
addChildrenToGroup(getFirstIndexOfDbActionToAdd(), existing, GroupsOfChildren.INITIALIZATION_SQL)
//TODO shall we check for duplications???

val already = this.sqlInitialization.filter { it.representExistingData }

val (toAdd, duplicates) = existing.partition {x ->
already.none { it.geInsertionId() == x.geInsertionId() }
}

if(toAdd.isNotEmpty()) {
addChildrenToGroup(getFirstIndexOfDbActionToAdd(), toAdd, GroupsOfChildren.INITIALIZATION_SQL)
}

skipped += duplicates.size
}

if(others.isNotEmpty()) {
Expand All @@ -431,6 +454,8 @@ abstract class EnterpriseIndividual(
}
addChildrenToGroup(pos, others, GroupsOfChildren.INITIALIZATION_SQL)
}

return skipped
}

fun addInitializingScheduleTaskActions(relativePosition: Int=-1, actions: List<Action>){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1034,20 +1034,23 @@ class StringGene(
}
}

//TODO would need updating...
// if(other is StringGene) {
// this.selectedSpecialization = other.selectedSpecialization
//
// this.specializations.clear()
// this.specializations.addAll(other.specializations)
//
// killAllChildren()
// addChildren(other.specializationGenes.map { it.copy() })
//
// this.tainted = other.tainted
if(other is StringGene) {
this.value = other.value
this.selectedSpecialization = other.selectedSpecialization

this.specializations.clear()
this.specializations.addAll(other.specializations)

killAllChildren()
val adopted = other.specializationGenes.map { it.copy() }
adopted.forEach { it.resetLocalIdRecursively()}
addChildren(adopted)

this.tainted = other.tainted
//TODO NOT sure if should handle this???
// this.bindingIds.clear()
// this.bindingIds.addAll(other.bindingIds)
// }
}

return true
}
Expand Down
7 changes: 6 additions & 1 deletion core/src/main/kotlin/org/evomaster/core/sql/SqlAction.kt
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,13 @@ class SqlAction(
return genes
}


fun seeGenesForInsertion(excludeColumn: List<String>) : List<out Gene>{
if (representExistingData) throw IllegalStateException("This action is representExistingData, and seeGenesForInsertion is not applicable")

if (representExistingData){
throw IllegalStateException("This action is representExistingData, and seeGenesForInsertion is not applicable")
}

return selectedColumns.mapIndexed { index, column ->
if (excludeColumn.any { c-> c.equals(column.name, ignoreCase = true) }) -1
else index
Expand Down
15 changes: 12 additions & 3 deletions core/src/main/kotlin/org/evomaster/core/sql/SqlActionUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ object SqlActionUtils {
*
* Returns true if the action list was fixed without removing any action.
* Returns false if actions needed to be removed
*
* WARNING: if there are side-effects on the list, ie, actions are removed, then might need to call
* resetInitializingActions() to make such changes be applied to the original individual,
*/
fun repairBrokenDbActionsList(actions: MutableList<SqlAction>,
randomness: Randomness,
Expand Down Expand Up @@ -372,11 +375,17 @@ object SqlActionUtils {
*/

val pkGenes = action.seeTopGenes()
.filterIsInstance<SqlPrimaryKeyGene>()
.mapNotNull { it.getWrappedGene(SqlPrimaryKeyGene::class.java) }
//.filterIsInstance<SqlPrimaryKeyGene>()

if(pkGenes.isEmpty()){
return null
}

val pk = pkGenes.sortedBy { it.name }
.map { it.name + "=" + getStringValue(it, all) }
.joinToString("__")
.joinToString("__") {
it.name + "=" + getStringValue(it, all)
}

val existing = pksValues.getOrPut(tableName) { mutableSetOf() }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import org.junit.jupiter.api.Test

class RestIndividualBuilderTest {


@Test
fun mergeCombinesMainActionsAndKeepsOrder() {
// create two simple RestCallAction with no parameters
Expand Down Expand Up @@ -127,15 +128,15 @@ class RestIndividualBuilderTest {
val sql2 = SqlAction(
table1,
setOf(col),
1L,
2L,
computedGenes = listOf(IntegerGene("ID", 2)),
representExistingData = false
)

val sql3 = SqlAction(
table2,
setOf(col),
1L,
3L,
computedGenes = listOf(
SqlPrimaryKeyGene(
"ID", TableId("T2"),
Expand All @@ -148,7 +149,7 @@ class RestIndividualBuilderTest {
val sql4 = SqlAction(
table2,
setOf(col),
1L,
4L,
computedGenes = listOf(IntegerGene("ID", 4)),
representExistingData = false
)
Expand Down Expand Up @@ -190,4 +191,118 @@ class RestIndividualBuilderTest {
}



@Test
fun testMergeInitActionsWithDuplicatedExistingData() {
// create two simple RestCallAction with no parameters
val callA = RestCallAction("idA", HttpVerb.GET, RestPath("/a"), mutableListOf())
val callB = RestCallAction("idB", HttpVerb.GET, RestPath("/b"), mutableListOf())

// create a simple table/column for sql initialization
val col = Column(
"ID",
ColumnDataType.INT,
primaryKey = true,
databaseType = org.evomaster.client.java.controller.api.dto.database.schema.DatabaseType.H2,
unique = true
)
val table1 = Table(TableId("T1"), setOf(col), emptySet())
val table2 = Table(TableId("T2"), setOf(col), emptySet())


val sql1 = SqlAction(
table1,
setOf(col),
1L,
computedGenes = listOf(
SqlPrimaryKeyGene(
"ID",
TableId("T1"),
ImmutableDataHolderGene("ID", "1", inQuotes = false),
uniqueId = 1L
)
),
representExistingData = true
)
val sql2 = SqlAction(
table1,
setOf(col),
2L,
computedGenes = listOf(IntegerGene("ID", 2)),
representExistingData = false
)

val sql3 = SqlAction(
table2,
setOf(col),
3L,
computedGenes = listOf(
SqlPrimaryKeyGene(
"ID", TableId("T2"),
ImmutableDataHolderGene("ID", "3", inQuotes = false),
uniqueId = 2L
)
),
representExistingData = true
)
val sql4 = SqlAction(
table2,
setOf(col),
4L,
computedGenes = listOf(IntegerGene("ID", 4)),
representExistingData = false
)
val sql5 = SqlAction(
table2,
setOf(col),
5L,
computedGenes = listOf(
SqlPrimaryKeyGene(
"ID", TableId("T2"),
ImmutableDataHolderGene("ID", "5", inQuotes = false),
uniqueId = 2L
)
),
representExistingData = true
)


// build individuals from single actions with initialization SQL
val first = RestIndividual(actions = mutableListOf(callA), sampleType = SampleType.RANDOM)
val second = RestIndividual(actions = mutableListOf(callB), sampleType = SampleType.RANDOM)

first.addInitializingDbActions(0, listOf(sql5,sql1, sql2))
second.addInitializingDbActions(0, listOf(sql3,sql5.copy() as SqlAction, sql4))

// merge
val builder = RestIndividualBuilder.createIndependentBuilderForTests()
val merged = builder.merge(first, second)
merged.verifyValidity()

// main executable actions should contain both actions in order
val mains = merged.seeMainExecutableActions()
assertEquals(2, mains.size)
assertEquals(callA.getName(), mains[0].getName())
assertEquals(callB.getName(), mains[1].getName())

// initializing SQL actions should not contain the duplicated existing sql5
val inits = merged.seeInitializingActions().filterIsInstance<SqlAction>()
assertEquals(5, inits.size)
/*
check their table names preserved and order: first's sql then second's sql.
however, existing data is always at the beginning
*/
assertTrue(inits[0].representExistingData)
assertTrue(inits[1].representExistingData)
assertTrue(inits[2].representExistingData)
assertFalse(inits[3].representExistingData)
assertFalse(inits[4].representExistingData)
assertEquals("T1", inits[3].table.name)
assertEquals("T2", inits[4].table.name)

// merged total actions should be sum of both initial individuals, minus the 1 duplicate
val before = first.seeAllActions().size + second.seeAllActions().size
assertEquals(before-1, merged.seeAllActions().size)
}

}
5 changes: 3 additions & 2 deletions release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ Under development in `master` branch.

### Fixed Bugs

- fixed a connection leak when authentication fails
- fixed few edge cases that led to crashes related to handling of MongoDB objects
- fixed a connection leak when authentication fails.
- fixed few edge cases that led to crashes related to handling of MongoDB objects.
- fixed bug in handling of SQL databases, where commands leading to inconsistent state (eg, duplicated keys) were not properly removed.

# Version 5.0.2

Expand Down