Skip to content

Commit 21ebf4e

Browse files
authored
Merge pull request #1605 from WebFuzzing/N-FlakyHandle
N flaky handle
2 parents 12d9ad9 + 346f5c3 commit 21ebf4e

12 files changed

Lines changed: 564 additions & 120 deletions

File tree

core-tests/e2e-tests/spring/spring-rest-bb/src/test/kotlin/org/evomaster/e2etests/spring/rest/bb/flakinessdetect/FlakinessDetectBBEMTest.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,12 @@ class FlakinessDetectBBEMTest : SpringTestBase() {
3737
){ args: MutableList<String> ->
3838

3939
setOption(args, "handleFlakiness", "true")
40+
setOption(args, "execNumForDetectFlakiness", "1")
4041

4142
val solution = initAndRun(args)
4243

4344
assertTrue(solution.individuals.isNotEmpty())
4445

4546
}
4647
}
47-
}
48+
}

core-tests/e2e-tests/spring/spring-rest-openapi-v3/src/main/kotlin/com/foo/rest/examples/spring/openapi/v3/flakinessdetect/FlakinessDetectRest.kt

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import org.springframework.web.bind.annotation.RestController
1010
import java.time.LocalDateTime
1111
import java.time.format.DateTimeFormatter
1212
import java.util.UUID
13+
import java.util.concurrent.atomic.AtomicInteger
1314
import kotlin.math.abs
1415
import kotlin.math.max
1516
import kotlin.math.min
@@ -21,6 +22,7 @@ class FlakinessDetectRest {
2122
companion object{
2223
val formatter = DateTimeFormatter.ofPattern("HH:mm:ss.SSS yyyy-MM-dd EEEE 'Week' ww")
2324
private val START_UP_OBJECT_TAG = arrayOf(javax.validation.constraints.Pattern.Flag.CASE_INSENSITIVE).toString()
25+
private val MULTI_EXECUTION_COUNTER = AtomicInteger(0)
2426
}
2527
@GetMapping(path = ["/objectFlag"])
2628
fun getEmptyFlag() : ResponseEntity<String> {
@@ -54,6 +56,19 @@ class FlakinessDetectRest {
5456
return ResponseEntity.ok(FlakinessDetectData(msg, num))
5557
}
5658

59+
@GetMapping(path = ["/multiexecution"])
60+
fun getMultiExecution() : ResponseEntity<MultiExecutionData> {
61+
val index = MULTI_EXECUTION_COUNTER.getAndIncrement() % 3
62+
63+
return ResponseEntity.ok(
64+
when (index) {
65+
0 -> MultiExecutionData("same", "a", "b")
66+
1 -> MultiExecutionData("same", "x", "b")
67+
else -> MultiExecutionData("same", "a", "y")
68+
}
69+
)
70+
}
71+
5772
@GetMapping("/price/estimate")
5873
fun estimatePrice(@RequestParam base: Int): Map<String, Int> {
5974
val randomJitter = randomInt(1000)
@@ -103,4 +118,10 @@ data class TimeAgoData(
103118
val calculatedPastTime: String
104119
)
105120

106-
class EmptyForFlag(val flag: String)
121+
data class MultiExecutionData(
122+
val stable: String,
123+
val first: String,
124+
val second: String
125+
)
126+
127+
class EmptyForFlag(val flag: String)

core-tests/e2e-tests/spring/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/flakinessdetect/FlakinessDetectBlackboxEMTest.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class FlakinessDetectBlackboxEMTest : SpringTestBase() {
3636

3737

3838
setOption(args, "handleFlakiness", "true")
39+
setOption(args, "execNumForDetectFlakiness", "1")
3940

4041
// we may still need to specify info in non bb-e2etest
4142
setOption(args, "blackBox", "true")
@@ -52,4 +53,4 @@ class FlakinessDetectBlackboxEMTest : SpringTestBase() {
5253

5354
}
5455
}
55-
}
56+
}

core-tests/e2e-tests/spring/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/flakinessdetect/FlakinessDetectEMTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class FlakinessDetectEMTest : SpringTestBase() {
3737

3838
setOption(args, "minimize", "true")
3939
setOption(args, "handleFlakiness", "true")
40+
setOption(args, "execNumForDetectFlakiness", "1")
4041

4142

4243
val solution = initAndRun(args)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package org.evomaster.e2etests.spring.openapi.v3.flakinessdetect
2+
3+
import com.foo.rest.examples.spring.openapi.v3.flakinessdetect.FlakinessDetectController
4+
import org.evomaster.e2etests.spring.openapi.v3.SpringTestBase
5+
import org.junit.jupiter.api.Assertions.assertTrue
6+
import org.junit.jupiter.api.BeforeAll
7+
import org.junit.jupiter.api.Test
8+
9+
class FlakinessDetectWithMultiExecEMTest : SpringTestBase() {
10+
11+
companion object {
12+
@BeforeAll
13+
@JvmStatic
14+
fun init() {
15+
initClass(FlakinessDetectController())
16+
}
17+
}
18+
19+
@Test
20+
fun testRunEMWithMultipleFlakinessExecutions() {
21+
22+
val outputFolder = "FlakinessDetectMultipleExecutionsEM"
23+
val outputClass = "org.foo.FlakinessDetectMultipleExecutionsEM"
24+
25+
runTestHandlingFlakyAndCompilation(
26+
outputFolder,
27+
outputClass,
28+
30,
29+
true
30+
) { args: MutableList<String> ->
31+
32+
setOption(args, "minimize", "true")
33+
setOption(args, "handleFlakiness", "true")
34+
setOption(args, "execNumForDetectFlakiness", "2")
35+
setOption(args, "endpointFocus", "/api/flakinessdetect/multiexecution")
36+
37+
val solution = initAndRun(args)
38+
39+
assertTrue(solution.individuals.isNotEmpty())
40+
assertTextInTests(outputFolder, outputClass, "Flaky value of field \"'first'\"")
41+
assertTextInTests(outputFolder, outputClass, "Flaky value of field \"'second'\"")
42+
}
43+
}
44+
}

core/src/main/kotlin/org/evomaster/core/EMConfig.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2793,6 +2793,17 @@ class EMConfig {
27932793
"Note that flakiness is now supported only for fuzzing REST APIs")
27942794
var handleFlakiness = false
27952795

2796+
@Experimental
2797+
@DependsOnTrueFor("handleFlakiness")
2798+
@Cfg("Specify whether to infer potential flakiness statically from response values, such as timestamps, UUIDs, hashes and runtime-specific messages.")
2799+
var enableStaticFlakyInference = true
2800+
2801+
@Experimental
2802+
@Min(0.0)
2803+
@DependsOnTrueFor("handleFlakiness")
2804+
@Cfg("Specify the number of re-executions for detecting flakiness in tests. Set to 0 to disable re-execution based flakiness detection.")
2805+
var execNumForDetectFlakiness = 1
2806+
27962807
@Experimental
27972808
@Cfg("Use environment variables to define the paths required by External Drivers. " +
27982809
"This is necessary when the generated tests are executed on the different machine. " +

core/src/main/kotlin/org/evomaster/core/Main.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ class Main {
451451
epc.markStartingFlakiness()
452452

453453
val flakinessDetector = injector.getInstance(Key.get(object : TypeLiteral<FlakinessDetector<RestIndividual>>() {}))
454-
flakinessDetector.reexecuteToDetectFlakiness()
454+
flakinessDetector.applyPhase()
455455
} else -> {
456456
LoggingUtil.getInfoLogger()
457457
.warn("Flakiness detection phase currently not handled for problem type: ${config.problemType}")

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -847,15 +847,15 @@ abstract class HttpWsTestCaseWriter : ApiTestCaseWriter() {
847847
lines.append("JsonConvert.DeserializeObject(await $responseVariableName.Content.ReadAsStringAsync());")
848848
}
849849

850-
handleJsonStringAssertion(bodyString, res.getFlakyBody(), lines, bodyVarName, res.getTooLargeBody())
850+
handleJsonStringAssertion(bodyString, res.getFlakyBodies()?.let { res.getMergedFlakyBody() }, lines, bodyVarName, res.getTooLargeBody())
851851

852852
} else if (type.isCompatible(MediaType.TEXT_PLAIN_TYPE)) {
853853

854854
if (format.isCsharp()) {
855855
lines.append("await $responseVariableName.Content.ReadAsStringAsync();")
856856
}
857857

858-
handleTextPlainTextAssertion(bodyString, res.getFlakyBody(), lines, bodyVarName)
858+
handleTextPlainTextAssertion(bodyString, res.getFlakyBodies()?.let { res.getMergedFlakyBody() }, lines, bodyVarName)
859859
} else {
860860
if (format.isCsharp()) {
861861
lines.append("await $responseVariableName.Content.ReadAsStringAsync();")

0 commit comments

Comments
 (0)