Skip to content

Commit edbbfff

Browse files
authored
Merge branch 'master' into ssrf-final-fixes
2 parents 0b78370 + e063898 commit edbbfff

8 files changed

Lines changed: 356 additions & 39 deletions

File tree

core/src/main/kotlin/org/evomaster/core/output/service/RestTestCaseWriter.kt

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import org.evomaster.core.output.Lines
66
import org.evomaster.core.output.SqlWriter
77
import org.evomaster.core.output.TestCase
88
import org.evomaster.core.output.TestWriterUtils
9+
import org.evomaster.core.problem.api.param.Param
910
import org.evomaster.core.problem.enterprise.EnterpriseActionResult
1011
import org.evomaster.core.problem.httpws.HttpWsAction
1112
import org.evomaster.core.problem.httpws.HttpWsCallResult
@@ -15,12 +16,18 @@ import org.evomaster.core.problem.rest.data.RestCallResult
1516
import org.evomaster.core.problem.rest.data.RestIndividual
1617
import org.evomaster.core.problem.rest.link.RestLinkParameter
1718
import org.evomaster.core.problem.rest.param.BodyParam
19+
import org.evomaster.core.problem.rest.param.HeaderParam
20+
import org.evomaster.core.problem.rest.param.PathParam
21+
import org.evomaster.core.problem.rest.param.QueryParam
1822
import org.evomaster.core.problem.rest.service.CallGraphService
1923
import org.evomaster.core.search.action.Action
2024
import org.evomaster.core.search.action.ActionResult
2125
import org.evomaster.core.search.EvaluatedIndividual
2226
import org.evomaster.core.search.Individual
27+
import org.evomaster.core.search.gene.collection.EnumGene
28+
import org.evomaster.core.search.gene.interfaces.NamedExamplesGene
2329
import org.evomaster.core.search.gene.utils.GeneUtils
30+
import org.evomaster.core.search.gene.wrapper.ChoiceGene
2431
import org.evomaster.core.utils.StringUtils
2532
import org.slf4j.LoggerFactory
2633
import java.nio.file.Path
@@ -542,6 +549,25 @@ class RestTestCaseWriter : HttpWsTestCaseWriter {
542549
return ind.seeFullTreeGenes()
543550
.filter { it.name == RestActionBuilderV3.EXAMPLES_NAME }
544551
.filter { it.staticCheckIfImpactPhenotype() }
545-
.map { it.getValueAsRawString() }
552+
.map {
553+
val name = if(it is NamedExamplesGene){
554+
"(${it.getValueName()?: "-"}) "
555+
} else {
556+
""
557+
}
558+
559+
val param = it.getFirstParent { p -> p is Param }
560+
val pName = when(param) {
561+
is QueryParam -> "QUERY: ${param.name}"
562+
is HeaderParam -> "HEADER: ${param.name}"
563+
is PathParam -> "PATH: ${param.name}"
564+
is BodyParam -> "BODY"
565+
else -> ""
566+
}
567+
568+
val value = it.getValueAsRawString()
569+
570+
"$name$pName -> $value"
571+
}
546572
}
547573
}

core/src/main/kotlin/org/evomaster/core/problem/rest/builder/RestActionBuilderV3.kt

Lines changed: 48 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -559,21 +559,26 @@ object RestActionBuilderV3 {
559559
example: Any?,
560560
examples: Map<String, Example>?,
561561
messages: MutableList<String>
562-
) : List<Any>{
562+
) : List<Pair<Any,String?>>{
563+
564+
/**
565+
* List of pairs value/name.
566+
* the name if optional, as only defined for "examples"
567+
*/
568+
val data = mutableListOf<Pair<Any, String?>>()
563569

564-
val data = mutableListOf<Any>()
565570
if(example != null){
566-
data.add(example)
571+
data.add(Pair(example,null))
567572
}
568573
if(!examples.isNullOrEmpty()){
569-
examples.values.forEach {
570-
val exm = if(it.`$ref` != null){
571-
SchemaUtils.getReferenceExample(schemaHolder, currentSchema, it.`$ref`, messages)
574+
examples.entries.forEach {
575+
val exm = if(it.value.`$ref` != null){
576+
SchemaUtils.getReferenceExample(schemaHolder, currentSchema, it.value.`$ref`, messages)
572577
} else {
573-
it
578+
it.value
574579
}
575580
if(exm != null) {
576-
data.add(exm.value)
581+
data.add(Pair(exm.value, it.key))
577582
}
578583
}
579584
}
@@ -780,7 +785,7 @@ object RestActionBuilderV3 {
780785
referenceClassDef: String?,
781786
options: Options,
782787
isInPath: Boolean = false,
783-
examples: List<Any> = listOf(),
788+
examples: List<Pair<Any,String?>> = listOf(),
784789
messages: MutableList<String>
785790
): Gene {
786791

@@ -974,7 +979,7 @@ object RestActionBuilderV3 {
974979
history: Deque<String>,
975980
referenceTypeName: String?,
976981
options: Options,
977-
examples: List<Any>,
982+
examples: List<Pair<Any,String?>>,
978983
messages: MutableList<String>
979984
): Gene {
980985

@@ -1131,7 +1136,7 @@ object RestActionBuilderV3 {
11311136
history: Deque<String>,
11321137
referenceTypeName: String?,
11331138
options: Options,
1134-
examples: List<Any>,
1139+
examples: List<Pair<Any,String?>>,
11351140
messages: MutableList<String>
11361141
) : Gene{
11371142
/*
@@ -1237,7 +1242,7 @@ object RestActionBuilderV3 {
12371242
fields: List<Gene>,
12381243
additionalFieldTemplate: PairGene<StringGene, Gene>?,
12391244
referenceTypeName: String?,
1240-
otherExampleValues: List<Any>,
1245+
otherExampleValues: List<Pair<Any,String?>>,
12411246
messages: MutableList<String>
12421247
) : Gene{
12431248
if (fields.isEmpty()) {
@@ -1269,19 +1274,29 @@ object RestActionBuilderV3 {
12691274
val exampleValue = if(options.probUseExamples > 0) schema.example else null
12701275
val multiExampleValues = if(options.probUseExamples > 0) schema.examples else null
12711276

1272-
val examples = mutableListOf<ObjectGene>()
1277+
val examples = mutableListOf<Pair<ObjectGene,String?>>()
12731278
if(exampleValue != null){
12741279
duplicateObjectWithExampleFields(name,mainGene, exampleValue)?.let {
1275-
examples.add(it)
1280+
examples.add(Pair(it,null))
12761281
}
12771282
}
12781283
if(multiExampleValues != null ){
1279-
examples.addAll(multiExampleValues.mapNotNull { duplicateObjectWithExampleFields(name,mainGene, it) })
1284+
examples.addAll(multiExampleValues
1285+
.mapNotNull { duplicateObjectWithExampleFields(name,mainGene, it) }
1286+
.map { Pair(it, null) }
1287+
)
12801288
}
1281-
examples.addAll(otherExampleValues.mapNotNull { duplicateObjectWithExampleFields(name,mainGene, it) })
1289+
examples.addAll(otherExampleValues
1290+
.mapNotNull { duplicateObjectWithExampleFields(name,mainGene, it.first)
1291+
?.let { obj -> Pair(obj,it.second) }
1292+
}
1293+
)
1294+
1295+
val v = examples.map { it.first } //values
1296+
val n = examples.map{it.second} // names
12821297

12831298
val exampleGene = if(examples.isNotEmpty()){
1284-
ChoiceGene(EXAMPLES_NAME, examples)
1299+
ChoiceGene(EXAMPLES_NAME, v, valueNames = n)
12851300
} else null
12861301
val defaultGene = if(defaultValue != null){
12871302
duplicateObjectWithExampleFields("default", mainGene, defaultValue)
@@ -1372,7 +1387,7 @@ object RestActionBuilderV3 {
13721387
options: Options,
13731388
collectionTemplate: Gene?,
13741389
isInPath: Boolean,
1375-
examples: List<Any>,
1390+
examples: List<Pair<Any,String?>>,
13761391
messages: MutableList<String>
13771392
) : Gene{
13781393

@@ -1412,7 +1427,7 @@ object RestActionBuilderV3 {
14121427
collectionTemplate: Gene? = null,
14131428
//might need to add extra constraints if in path
14141429
isInPath: Boolean,
1415-
exampleObjects: List<Any>,
1430+
exampleObjects: List<Pair<Any,String?>>,
14161431
format: String? = null,
14171432
messages: MutableList<String>
14181433
) : Gene{
@@ -1544,10 +1559,12 @@ object RestActionBuilderV3 {
15441559
val exampleValue = if(options.probUseExamples > 0) schema.example else null
15451560
val multiExampleValues = if(options.probUseExamples > 0) schema.examples else null
15461561

1547-
val examples = mutableListOf<String>()
1562+
//value and optional name
1563+
val examples = mutableListOf<Pair<String,String?>>()
1564+
15481565
if(exampleValue != null) {
15491566
val raw = asRawString(exampleValue)
1550-
examples.add(raw)
1567+
examples.add(Pair(raw,null))
15511568
val arrayM = if(raw.startsWith("[")) "If you are wrongly passing to it an array of values, " +
15521569
"the parser would read it as an array string or simply ignore it. "
15531570
else ""
@@ -1558,9 +1575,9 @@ object RestActionBuilderV3 {
15581575
}
15591576
if(multiExampleValues != null && multiExampleValues.isNotEmpty()){
15601577
//possibly bug in parser, but it was reading strings values double-quoted in this case
1561-
examples.addAll(multiExampleValues.map { asRawString(it) })
1578+
examples.addAll(multiExampleValues.map { Pair(asRawString(it), null) })
15621579
}
1563-
examples.addAll( exampleObjects.map { asRawString(it) })
1580+
examples.addAll( exampleObjects.map { Pair(asRawString(it.first), it.second) })
15641581

15651582

15661583
val defaultGene = if(defaultValue != null){
@@ -1581,15 +1598,20 @@ object RestActionBuilderV3 {
15811598
}
15821599
} else null
15831600

1601+
//values
1602+
val v = examples.map { it.first }
1603+
//optional names
1604+
val n = examples.map { it.second }
1605+
15841606
val exampleGene = if(examples.isNotEmpty()){
15851607
when{
15861608
NumberGene::class.java.isAssignableFrom(geneClass)
1587-
-> EnumGene(EXAMPLES_NAME, examples,0,true)
1609+
-> EnumGene(EXAMPLES_NAME, v,0,true, n)
15881610

15891611
geneClass == StringGene::class.java
15901612
|| geneClass == Base64StringGene::class.java
15911613
|| geneClass == RegexGene::class.java
1592-
-> EnumGene<String>(EXAMPLES_NAME, examples,0,false)
1614+
-> EnumGene<String>(EXAMPLES_NAME, v,0,false, n)
15931615

15941616
//TODO Arrays
15951617
else -> {
@@ -1692,7 +1714,7 @@ object RestActionBuilderV3 {
16921714
currentSchema: SchemaOpenAPI,
16931715
history: Deque<String> = ArrayDeque(),
16941716
options: Options,
1695-
examples: List<Any>,
1717+
examples: List<Pair<Any,String?>>,
16961718
messages: MutableList<String>
16971719
): Gene {
16981720

core/src/main/kotlin/org/evomaster/core/search/algorithms/SteadyStateGeneticAlgorithm.kt

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@ import org.evomaster.core.search.Individual
55
import org.evomaster.core.search.algorithms.wts.WtsEvalIndividual
66
import org.evomaster.core.search.service.SearchAlgorithm
77
import kotlin.math.max
8-
//TODO: Note that this class is not fully tested.
9-
// It needs to be thoroughly verified whether this truly adheres to the intended algorithm.
108
/**
11-
* An implementation of the Steady-State Genetic Algorithm (SSGA).
9+
* An implementation of the Steady-State Genetic Algorithm (SSGA).
1210
*
1311
* Unlike Standard GA, which replaces the entire population in each generation,
1412
* Steady-State GA updates the population incrementally by replacing a small number
15-
* of individuals at a time (typically just 1 or 2).
13+
* of individuals at a time:
14+
* Only replaces selected parents with offspring if the offspring are better
1615
*
1716
* This class inherits from StandardGeneticAlgorithm to reuse shared components,
1817
* but overrides search behavior to follow steady-state principles.
@@ -33,6 +32,12 @@ class SteadyStateGeneticAlgorithm<T> : StandardGeneticAlgorithm<T>() where T : I
3332
* - Replace the parents with the offspring only if the offspring are fitter.
3433
*/
3534
override fun searchOnce() {
35+
// Lifecycle: start generation
36+
beginGeneration()
37+
// Freeze objectives for this generation
38+
frozenTargets = archive.notCoveredTargets()
39+
// Start single steady-state step
40+
beginStep()
3641
// Select two parents from the population
3742
val p1 = tournamentSelection()
3843
val p2 = tournamentSelection()
@@ -55,14 +60,17 @@ class SteadyStateGeneticAlgorithm<T> : StandardGeneticAlgorithm<T>() where T : I
5560
}
5661

5762
// Only replace parents with offspring if the offspring are better
58-
if (max(o1.calculateCombinedFitness(), o2.calculateCombinedFitness()) >
59-
max(p1.calculateCombinedFitness(), p2.calculateCombinedFitness())) {
63+
if (max(score(o1), score(o2)) >
64+
max(score(p1), score(p2))) {
6065

6166
// Replace both parents in the population
6267
population.remove(p1)
6368
population.remove(p2)
6469
population.add(o1)
6570
population.add(o2)
6671
}
72+
// End step and generation
73+
endStep()
74+
endGeneration()
6775
}
6876
}

core/src/main/kotlin/org/evomaster/core/search/gene/collection/EnumGene.kt

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package org.evomaster.core.search.gene.collection
22

33
import org.evomaster.core.output.OutputFormat
44
import org.evomaster.core.search.gene.Gene
5+
import org.evomaster.core.search.gene.interfaces.NamedExamplesGene
56
import org.evomaster.core.search.gene.string.StringGene
67
import org.evomaster.core.search.gene.root.SimpleGene
78
import org.evomaster.core.search.gene.utils.GeneUtils
@@ -30,8 +31,13 @@ class EnumGene<T : Comparable<T>>(
3031
* to avoid specifying exact types. Still, should not be printed out as string.
3132
* Recall that an enum is just a group of constants that cannot be mutated
3233
*/
33-
private val treatAsNotString : Boolean = false
34-
) : SimpleGene(name) {
34+
private val treatAsNotString : Boolean = false,
35+
/**
36+
* An optional list of 'names' for each/some of the values in this enumeration.
37+
* This is usually just extra information, eg, to recognize named "examples" in OpenAPI schemas
38+
*/
39+
private val valueNames: List<String?>? = null
40+
) : SimpleGene(name), NamedExamplesGene {
3541

3642
companion object {
3743

@@ -81,6 +87,10 @@ class EnumGene<T : Comparable<T>>(
8187
if (index < 0 || index >= values.size) {
8288
throw IllegalArgumentException("Invalid index: $index")
8389
}
90+
91+
if(valueNames != null && valueNames.size != values.size) {
92+
throw IllegalArgumentException("Invalid valueNames size: ${valueNames.size}!=${values.size}")
93+
}
8494
}
8595

8696
if(treatAsNotString && values.isNotEmpty() && values[0] !is String){
@@ -98,7 +108,7 @@ class EnumGene<T : Comparable<T>>(
98108

99109
override fun copyContent(): Gene {
100110
//recall: "values" is immutable
101-
return EnumGene<T>(name, values, index, treatAsNotString)
111+
return EnumGene<T>(name, values, index, treatAsNotString, valueNames)
102112
}
103113

104114
override fun setValueWithRawString(value: String) {
@@ -183,6 +193,10 @@ class EnumGene<T : Comparable<T>>(
183193
return values[index].toString()
184194
}
185195

196+
override fun getValueName(): String?{
197+
return valueNames?.get(index)
198+
}
199+
186200
override fun copyValueFrom(other: Gene): Boolean {
187201
if (other !is EnumGene<*>) {
188202
throw IllegalArgumentException("Invalid gene type ${other.javaClass}")
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package org.evomaster.core.search.gene.interfaces
2+
3+
/**
4+
* A gene representing possible different examples provided by the user.
5+
* Such examples might have unique names/ids used to easily identify them
6+
*/
7+
interface NamedExamplesGene {
8+
9+
fun getValueName(): String?
10+
}

0 commit comments

Comments
 (0)