Skip to content

Commit

Permalink
yet on the journey to refactor TableId
Browse files Browse the repository at this point in the history
  • Loading branch information
arcuri82 committed Jan 17, 2025
1 parent dbd2e90 commit 3483d4c
Show file tree
Hide file tree
Showing 11 changed files with 157 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ abstract class ApiWsFitness<T> : EnterpriseFitness<T>() where T : Individual {
@Inject
protected lateinit var writer: TestSuiteWriter

@Inject
protected lateinit var sampler: Sampler<T>

lateinit var infoDto: SutInfoDto

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ abstract class EnterpriseFitness<T> : FitnessFunction<T>() where T : Individual
@Inject
protected lateinit var searchTimeController: SearchTimeController

@Inject
protected lateinit var sampler: EnterpriseSampler<T>

/**
* @param allSqlActions specified the db actions to be executed
Expand Down Expand Up @@ -255,10 +257,13 @@ abstract class EnterpriseFitness<T> : FitnessFunction<T>() where T : Individual
if (configuration.extractSqlExecutionInfo) {
for (i in 0 until dto.extraHeuristics.size) {
val extra = dto.extraHeuristics[i]
val databaseExecution = DatabaseExecution.fromDto(extra.sqlSqlExecutionsDto)
fv.setDatabaseExecution(i, databaseExecution)
if (databaseExecution.sqlParseFailureCount>0) {
statistics.reportSqlParsingFailures(databaseExecution.sqlParseFailureCount)
val sdto = extra.sqlSqlExecutionsDto
if(sdto != null) {
val databaseExecution = DatabaseExecution.fromDto(sdto, sampler.sqlInsertBuilder!!.getTableNames())
fv.setDatabaseExecution(i, databaseExecution)
if (databaseExecution.sqlParseFailureCount > 0) {
statistics.reportSqlParsingFailures(databaseExecution.sqlParseFailureCount)
}
}
}
fv.aggregateDatabaseData()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import org.evomaster.core.search.gene.ObjectGene
import org.evomaster.core.search.gene.sql.SqlForeignKeyGene
import org.evomaster.core.search.gene.sql.SqlPrimaryKeyGene
import org.evomaster.core.search.service.Randomness
import org.evomaster.core.sql.SqlActionUtils
import org.evomaster.core.sql.schema.TableId
import org.slf4j.Logger
import org.slf4j.LoggerFactory
Expand Down Expand Up @@ -666,7 +667,9 @@ open class RestResourceNode(
/**
* @return derived tables
*/
fun getDerivedTables() : Set<String> = resourceToTable.derivedMap.flatMap { it.value.map { m->m.targetMatched } }.toHashSet()
fun getDerivedTables(all: Set<TableId>) : Set<TableId> = resourceToTable.derivedMap
.flatMap { it.value.mapNotNull { m-> SqlActionUtils.getTableKey(all, m.targetMatched) } }
.toHashSet()

/**
* @return is any POST, GET, PATCH, DELETE, PUT action?
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.evomaster.core.problem.rest.resource.dependency

import org.evomaster.core.problem.rest.RestPath
import org.evomaster.core.sql.schema.TableId

/**
* @param path is a list of path(s), which can be parsed with [RelatedTo.parseMultipleKey]
Expand Down Expand Up @@ -49,8 +50,11 @@ open class ResourceRelatedToResources(
* Note that related table might be derived based on token parser, not confirmed regarding evomaster driver.
* [confirmedSet] is used to represent whether the mutual relation is confirmed.
*/
class MutualResourcesRelations(mutualResources: List<String>, probability: Double, var referredTables : MutableSet<String> = mutableSetOf())
: ResourceRelatedToResources(mutualResources, mutualResources.toMutableList(), probability, ""){
class MutualResourcesRelations(
mutualResources: List<String>,
probability: Double,
var referredTables : MutableSet<TableId> = mutableSetOf()
) : ResourceRelatedToResources(mutualResources, mutualResources.toMutableList(), probability, ""){

override fun getName(): String {
return "MutualRelations:${notateKey()}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.evomaster.core.sql.SQLKey
import org.evomaster.core.problem.rest.param.BodyParam
import org.evomaster.core.problem.api.param.Param
import org.evomaster.core.problem.util.inference.model.MatchedInfo
import org.evomaster.core.sql.DatabaseExecution
import org.evomaster.core.sql.SqlActionUtils
import org.evomaster.core.sql.schema.TableId

Expand All @@ -17,7 +18,7 @@ class ResourceRelatedToTable(val key: String) {
companion object {
private const val FROM_EVO_DTO = "____FROM_DTO____"

fun generateFromDtoMatchedInfo(table: String) : MatchedInfo = MatchedInfo(FROM_EVO_DTO, table, 1.0, -1, -1)
fun generateFromDtoMatchedInfo(table: TableId) : MatchedInfo = MatchedInfo(FROM_EVO_DTO, table.getFullQualifyingTableName(), 1.0, -1, -1)
}
/**
* key is table name
Expand Down Expand Up @@ -58,16 +59,17 @@ class ResourceRelatedToTable(val key: String) {
private val actionToTables : MutableMap<String, MutableList<ActionRelatedToTable>> = mutableMapOf()


fun updateActionRelatedToTable(verb : String, dto: SqlExecutionsDto, existingTables : Set<String>) : Boolean{
fun updateActionRelatedToTable(verb : String, de: DatabaseExecution, existingTables : Set<TableId>) : Boolean{

val tables = mutableListOf<String>()
.plus(dto.deletedData)
.plus(dto.updatedData.keys)
.plus(dto.insertedData.keys)
.plus(dto.queriedData.keys)
.filter { x ->
existingTables.any { x.equals(it, true) }
}.toHashSet()
val tables = mutableListOf<TableId>()
.plus(de.deletedData)
.plus(de.updatedData.keys)
.plus(de.insertedData.keys)
.plus(de.queriedData.keys)
// .filter { x ->
// existingTables.any { x.equals(it, true) }
// }
.toHashSet()

if (tables.isEmpty()) return false

Expand All @@ -82,10 +84,10 @@ class ResourceRelatedToTable(val key: String) {
actionToTables[verb]!!.add(access)
}

access.updateTableWithFields(dto.deletedData.associateWith { mutableSetOf<String>() }, SQLKey.DELETE)
access.updateTableWithFields(dto.insertedData, SQLKey.INSERT)
access.updateTableWithFields(dto.queriedData, SQLKey.SELECT)
access.updateTableWithFields(dto.updatedData, SQLKey.UPDATE)
access.updateTableWithFields(de.deletedData.associateWith { mutableSetOf<String>() }, SQLKey.DELETE)
access.updateTableWithFields(de.insertedData, SQLKey.INSERT)
access.updateTableWithFields(de.queriedData, SQLKey.SELECT)
access.updateTableWithFields(de.updatedData, SQLKey.UPDATE)

return doesUpdateParamTable
}
Expand Down Expand Up @@ -222,15 +224,15 @@ class ActionRelatedToTable(
* key is table name
* value is how it accessed by dbaction
*/
val tableWithFields: MutableMap<String, MutableList<AccessTable>> = mutableMapOf()
val tableWithFields: MutableMap<TableId, MutableList<AccessTable>> = mutableMapOf()
) {


/**
* key of result is table name
* value of result is a set of manipulated columns
*/
fun updateTableWithFields(results : Map<String, Set<String>>, method: SQLKey) {
fun updateTableWithFields(results : Map<TableId, Set<String>>, method: SQLKey) {
var doesUpdateTarget = false
results.forEach { t, u ->
doesUpdateTarget = doesUpdateTarget || tableWithFields.containsKey(t)
Expand All @@ -245,7 +247,7 @@ class ActionRelatedToTable(
}
}

fun doesSubsume(tables : Set<String>, subsumeThis : Boolean) : Boolean{
fun doesSubsume(tables : Set<TableId>, subsumeThis : Boolean) : Boolean{
return if(subsumeThis) tables.toHashSet().containsAll(tableWithFields.keys)
else tableWithFields.keys.containsAll(tables)
}
Expand All @@ -255,7 +257,7 @@ class ActionRelatedToTable(
* @property table related table
* @property field what fields are assess by the sql command
*/
class AccessTable(val method : SQLKey, val table : String, val field : MutableSet<String>)
class AccessTable(val method : SQLKey, val table : TableId, val field : MutableSet<String>)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import org.evomaster.core.search.EvaluatedIndividual
import org.evomaster.core.search.service.AdaptiveParameterControl
import org.evomaster.core.search.service.Randomness
import org.evomaster.core.search.service.mutator.EvaluatedMutation
import org.evomaster.core.sql.DatabaseExecution
import org.evomaster.core.sql.schema.TableId
import org.slf4j.Logger
import org.slf4j.LoggerFactory
Expand Down Expand Up @@ -83,16 +84,18 @@ class ResourceDepManageService {
/*
TODO how to decide to remove relationship between resource and table
*/
val addedMap = mutableMapOf<String, MutableSet<String>>()
val removedMap = mutableMapOf<String, MutableSet<String>>()
val addedMap = mutableMapOf<String, MutableSet<TableId>>()
val removedMap = mutableMapOf<String, MutableSet<TableId>>()

restIndividual.seeMainExecutableActions().forEachIndexed { index, action ->
if (config.doesApplyNameMatching) updateParamInfo(action as RestCallAction, tables)
// size of extraHeuristics might be less than size of action due to failure of handling rest action
if (index < dto.extraHeuristics.size) {
val dbDto = dto.extraHeuristics[index].sqlSqlExecutionsDto
if (dbDto != null)
updateResourceToTable(action as RestCallAction, dbDto, tables, addedMap, removedMap)
if (dbDto != null) {
val de = DatabaseExecution.fromDto(dbDto, tables.keys)
updateResourceToTable(action, de, tables, addedMap, removedMap)
}
}
}
if (addedMap.isNotEmpty() || removedMap.isNotEmpty())
Expand All @@ -114,12 +117,20 @@ class ResourceDepManageService {
/**
* TODO remove false-derived dependencies based on feedback from evomaster driver
*/
private fun updateDependencyOnceResourceTableUpdate(addedMap: MutableMap<String, MutableSet<String>>, removedMap: MutableMap<String, MutableSet<String>>) {
private fun updateDependencyOnceResourceTableUpdate(
addedMap: MutableMap<String, MutableSet<TableId>>,
removedMap: MutableMap<String, MutableSet<TableId>>
) {

val groupTable = addedMap.flatMap { it.value }.toHashSet()
groupTable.forEach { table ->
val newRelatedResource = addedMap.filter { it.value.contains(table) }.keys
val previousResourcesWithTable = dependencies.values.flatMap { l -> l.filter { d->d is MutualResourcesRelations && d.referredTables.contains(table) }.flatMap { it.targets }}.toHashSet()
val previousResourcesWithTable = dependencies.values
.flatMap {
l -> l
.filter { d->d is MutualResourcesRelations && d.referredTables.contains(table) }
.flatMap { it.targets }
}.toHashSet()

var find = false
dependencies.values.forEach { rlist ->
Expand Down Expand Up @@ -170,16 +181,22 @@ class ResourceDepManageService {
}
}

private fun updateResourceToTable(action: RestCallAction, updated: Map<String, MutableSet<String>>, matchedWithVerb: Boolean, tables: Map<String, Table>,
addedMap: MutableMap<String, MutableSet<String>>, removedMap: MutableMap<String, MutableSet<String>>) {
private fun updateResourceToTable(
action: RestCallAction,
updated: Map<TableId, Set<String>>,
matchedWithVerb: Boolean,
tables: Map<TableId, Table>,
addedMap: MutableMap<String, MutableSet<TableId>>,
removedMap: MutableMap<String, MutableSet<TableId>>
) {
val ar = rm.getResourceNodeFromCluster(action.path.toString())
val rToTable = ar.resourceToTable

if (updated.isNotEmpty() && matchedWithVerb) {
val derivedTables = rToTable.getTablesInDerivedMap()

updated.forEach { (t, u) ->
if (derivedTables.any { it.equals(t, ignoreCase = true) }) {
if (derivedTables.any { it == t }) {
if (action.parameters.isNotEmpty() && u.isNotEmpty() && u.none { it == "*" }) {
action.parameters.forEach { p ->
val paramId = ar.getParamId(action.parameters, p)
Expand All @@ -191,8 +208,8 @@ class ResourceDepManageService {
}
}
} else {
val matchedInfo = ResourceRelatedToTable.generateFromDtoMatchedInfo(t.toLowerCase())
ar.resourceToTable.derivedMap.put(t, mutableListOf(matchedInfo))
val matchedInfo = ResourceRelatedToTable.generateFromDtoMatchedInfo(t)
ar.resourceToTable.derivedMap[t] = mutableListOf(matchedInfo)
action.parameters.forEach { p ->
val paramId = ar.getParamId(action.parameters, p)
val paramInfo = ar.paramsInfo[paramId].run {
Expand All @@ -204,13 +221,12 @@ class ResourceDepManageService {
val hasMatchedParam = SimpleDeriveResourceBinding.deriveRelatedTable(ar, paramId, paramInfo, mutableSetOf(t), p is BodyParam, -1, alltables = tables)
ar.resourceToTable.paramToTable[paramId]?.let { paramToTable ->
paramToTable.getRelatedColumn(t)?.apply {
paramToTable.confirmedColumn.addAll(this.intersect(u.filter { it != "*" }))
paramToTable.confirmedColumn.addAll(this.intersect(u.filter { it != "*" }.toSet()))
}
}
}

addedMap.getOrPut(ar.getName()) { mutableSetOf() }.add(t)

}

rToTable.confirmedSet.getOrPut(t) { true }
Expand All @@ -225,29 +241,25 @@ class ResourceDepManageService {

private fun updateResourceToTable(
action: RestCallAction,
dto: SqlExecutionsDto,
de: DatabaseExecution,
tables: Map<TableId, Table>,
addedMap: MutableMap<String, MutableSet<String>>,
removedMap: MutableMap<String, MutableSet<String>>
addedMap: MutableMap<String, MutableSet<TableId>>,
removedMap: MutableMap<String, MutableSet<TableId>>
) {

dto.insertedData.filter { u -> tables.any { it.key.toLowerCase() == u.key } }.let { added ->
updateResourceToTable(action, added, (action.verb == HttpVerb.POST || action.verb == HttpVerb.PUT), tables, addedMap, removedMap)
}

dto.updatedData.filter { u -> tables.any { it.key.toLowerCase() == u.key } }.let { updated ->
updateResourceToTable(action, updated, (action.verb == HttpVerb.PATCH || action.verb == HttpVerb.PUT), tables, addedMap, removedMap)
}
updateResourceToTable(action, de.insertedData, (action.verb == HttpVerb.POST || action.verb == HttpVerb.PUT), tables, addedMap, removedMap)
updateResourceToTable(action, de.updatedData, (action.verb == HttpVerb.PATCH || action.verb == HttpVerb.PUT), tables, addedMap, removedMap)
updateResourceToTable(action, de.deletedData.map { Pair(it, mutableSetOf<String>()) }.toMap(), (action.verb == HttpVerb.PATCH || action.verb == HttpVerb.PUT), tables, addedMap, removedMap)
updateResourceToTable(action, de.queriedData, true, tables, addedMap, removedMap)

dto.deletedData.filter { u -> tables.any { it.key.toLowerCase() == u } }.let { del ->
updateResourceToTable(action, del.map { Pair(it, mutableSetOf<String>()) }.toMap(), (action.verb == HttpVerb.PATCH || action.verb == HttpVerb.PUT), tables, addedMap, removedMap)
val relatedTable = rm.getResourceNodeFromCluster(action.path.toString())
.resourceToTable

}
dto.queriedData.filter { u -> tables.any { it.key.toLowerCase() == u.key } }.let { get ->
updateResourceToTable(action, get, true, tables, addedMap, removedMap)
}

rm.getResourceNodeFromCluster(action.path.toString()).resourceToTable.updateActionRelatedToTable(action.verb.toString(), dto, tables.keys)
relatedTable.updateActionRelatedToTable(
action.verb.toString(),
de,
tables.keys
)
}

/************************ derive dependency using parser ***********************************/
Expand All @@ -257,7 +269,11 @@ class ResourceDepManageService {
*/
fun initDependencyBasedOnDerivedTables(resourceCluster: ResourceCluster) {
resourceCluster.getTableInfo().keys.forEach { table ->
val mutualResources = resourceCluster.getCluster().values.filter { r -> r.getDerivedTables().any { e -> e.equals(table, ignoreCase = true) } }.map { it.getName() }.toList()
val mutualResources = resourceCluster.getCluster().values
.filter { r -> r.getDerivedTables(rm.sqlInsertBuilder!!.getTableNames()).any { e -> e == table } }
.map { it.getName() }
.toList()

if (mutualResources.isNotEmpty() && mutualResources.size > 1) {
val mutualRelation = MutualResourcesRelations(mutualResources, StringSimilarityComparator.SimilarityThreshold, mutableSetOf(table))

Expand All @@ -267,7 +283,7 @@ class ResourceDepManageService {
if (it == null)
relations.add(mutualRelation)
else
(it as MutualResourcesRelations).referredTables.add(table.toLowerCase())
(it as MutualResourcesRelations).referredTables.add(table)
}
}
}
Expand Down Expand Up @@ -1040,15 +1056,15 @@ class ResourceDepManageService {

if (allrelated.isNotEmpty() && randomness.nextBoolean(probability)){
val notincluded = allrelated.filterNot {
ind.seeInitializingActions().filterIsInstance<SqlAction>().any { d-> it.equals(d.table.name, ignoreCase = true) }
ind.seeInitializingActions().filterIsInstance<SqlAction>().any { d-> it == d.table.id }
}
//prioritize notincluded related ones with a probability 0.8
return if (notincluded.isNotEmpty() && randomness.nextBoolean(0.8)){
notincluded.toSet()
}else allrelated
}else{
val left = rm.getTableInfo().keys.filterNot {
ind.seeInitializingActions().filterIsInstance<SqlAction>().any { d-> it.equals(d.table.name, ignoreCase = true) }
ind.seeInitializingActions().filterIsInstance<SqlAction>().any { d-> it == d.table.id }
}
return if (left.isNotEmpty() && randomness.nextBoolean()) left.toSet()
else rm.getTableInfo().keys
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ class ResourceManageService {
private val excludedCluster : MutableMap<String, ExcludedResourceNode> = mutableMapOf()


private var sqlInsertBuilder : SqlInsertBuilder? = null
var sqlInsertBuilder : SqlInsertBuilder? = null
private set

/**
* init resource nodes based on [actionCluster] and [sqlInsertBuilder]
Expand Down Expand Up @@ -185,7 +186,7 @@ class ResourceManageService {
return
}

var employSQL = config.shouldGenerateSqlData() && hasDBHandler() && ar.getDerivedTables().isNotEmpty()
var employSQL = config.shouldGenerateSqlData() && hasDBHandler() && ar.getDerivedTables(sqlInsertBuilder!!.getTableNames()).isNotEmpty()
&& (forceSQLInsert || randomness.nextBoolean(config.probOfApplySQLActionToCreateResources))

var candidate = template
Expand Down
Loading

0 comments on commit 3483d4c

Please sign in to comment.