Skip to content

Commit 5a4d6e6

Browse files
authored
Merge pull request #1459 from WebFuzzing/ai-repair-targeted
handling targeted repairs
2 parents 24d9663 + 7ccfa4e commit 5a4d6e6

3 files changed

Lines changed: 69 additions & 6 deletions

File tree

core/src/main/kotlin/org/evomaster/core/problem/rest/classifier/InputField.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,14 @@ enum class InputFieldType{
99
* Represent a field in the input of a REST call, for which are aiming to learn its constraints
1010
*/
1111
data class InputField(
12+
/**
13+
* Eg, name of query parameter, or field in body payload.
14+
* For nested fields, used '.', eg, "address.city"
15+
*/
1216
val name : String,
1317
val type : InputFieldType
14-
)
18+
){
19+
fun isWholeBody() = type == InputFieldType.BODY && name.isEmpty()
20+
21+
}
1522

core/src/main/kotlin/org/evomaster/core/problem/rest/service/AIResponseClassifier.kt

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import org.evomaster.core.problem.rest.data.RestCallAction
66
import org.evomaster.core.problem.rest.data.RestCallResult
77
import org.evomaster.core.problem.rest.classifier.AIModel
88
import org.evomaster.core.problem.rest.classifier.AIResponseClassification
9+
import org.evomaster.core.problem.rest.classifier.InputFieldType
910
import org.evomaster.core.problem.rest.classifier.quantifier.ModelEvaluation
1011
import org.evomaster.core.problem.rest.classifier.deterministic.Deterministic400Classifier
1112
import org.evomaster.core.problem.rest.classifier.probabilistic.gaussian.Gaussian400Classifier
@@ -14,6 +15,8 @@ import org.evomaster.core.problem.rest.classifier.probabilistic.kde.KDE400Classi
1415
import org.evomaster.core.problem.rest.classifier.probabilistic.knn.KNN400Classifier
1516
import org.evomaster.core.problem.rest.classifier.probabilistic.nn.NN400Classifier
1617
import org.evomaster.core.problem.rest.data.Endpoint
18+
import org.evomaster.core.problem.rest.param.BodyParam
19+
import org.evomaster.core.search.gene.ObjectGene
1720
import org.evomaster.core.search.service.Randomness
1821
import org.slf4j.Logger
1922
import org.slf4j.LoggerFactory
@@ -295,20 +298,49 @@ class AIResponseClassifier : AIModel {
295298
return
296299
}
297300
}
298-
//TODO
299301
}
300302

301303
private fun repairAction(
302304
call: RestCallAction,
303305
classification: AIResponseClassification
304306
) {
305-
call.randomize(randomness, true)
306-
307307
/*
308-
TODO: in the future we might want to only modify the variables that break the constraints.
308+
We might want to only modify the variables that break the constraints.
309309
This information might be available when using a Decision Tree, but likely not for a Neural Network.
310-
Anyway, AIResponseClassification would need to be extended to handle this extra info, when available.
311310
*/
311+
if (classification.invalidFields.isEmpty()) {
312+
//no info available
313+
call.randomize(randomness, true)
314+
return
315+
}
316+
317+
for (field in classification.invalidFields) {
318+
when (field.type) {
319+
320+
InputFieldType.QUERY -> {
321+
val param = call.parameters.find { it.name == field.name }
322+
?: throw IllegalStateException("Field '${field.name}' is not referring to any valid query parameter")
323+
param.seeGenes()
324+
.filter { it.isMutable() }
325+
.forEach { it.randomize(randomness, true) }
326+
}
327+
328+
InputFieldType.BODY -> {
329+
val body = call.parameters.find{ it is BodyParam}
330+
?: throw IllegalStateException("Using field in body but no payload is defined")
331+
if(field.isWholeBody()){
332+
body.primaryGene().randomize(randomness, true)
333+
} else {
334+
//TODO if we going to handle other types of genes in payload, we need to extend this
335+
val payload = body.primaryGene() as ObjectGene
336+
val target = payload.getField(field.name)
337+
?: throw IllegalStateException("Field '${field.name}' is not referring to any valid payload")
338+
target.randomize(randomness, true)
339+
}
340+
}
341+
}
342+
}
343+
call.postRandomizedChecks(randomness)
312344
}
313345

314346
/**

core/src/main/kotlin/org/evomaster/core/search/gene/ObjectGene.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,4 +755,28 @@ open class ObjectGene(
755755
if (gene !is PairGene<*,*>) return false
756756
return additionalFields?.contains(gene) ?: false
757757
}
758+
759+
/**
760+
* Return gene representing given field.
761+
* Using "." for nested fields, eg "address.city"
762+
*/
763+
fun getField(pathName: String) : Gene?{
764+
765+
val tokens = pathName.split(",")
766+
val current = tokens[0]
767+
val target = fixedFields.find { it.name == current}
768+
?: additionalFields?.find { it.first.getValueAsRawString() == current}?.second?.gene
769+
?: return null
770+
771+
if(tokens.size == 1){
772+
return target
773+
}
774+
775+
//TODO if we add getField in an interface to other genes as well, then we should use such interface here
776+
if(target !is ObjectGene){
777+
return null
778+
}
779+
780+
return target.getField(tokens.subList(1, tokens.size).joinToString("."))
781+
}
758782
}

0 commit comments

Comments
 (0)