Skip to content

Commit 526204c

Browse files
authored
Merge pull request #1421 from WebFuzzing/builder-performance
Builder performance
2 parents 177436a + d205699 commit 526204c

11 files changed

Lines changed: 100 additions & 30 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ env:
4242
build-jdk: 17
4343
retention-days: 5
4444
debug: false # put to true if need to debug a specific test
45-
debugTestName: "org.evomaster.e2etests.spring.examples.sort.SortEMTest" # replace with test to debug
45+
debugTestName: "org.evomaster.core.problem.rest.SamplerVerifierTest" # replace with test to debug
4646

4747
# This build is quite expensive (some hours), so we run it whole only on some JVM versions and OSs.
4848
# For the moment, we need to support JVM 8 and all following LTS versions (e.g, 11 and 17).

client-java/instrumentation/src/main/java/org/evomaster/client/java/instrumentation/AdditionalInfo.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,10 @@ public void setRawAccessOfHttpBodyPayload(boolean rawAccessOfHttpBodyPayload) {
170170

171171
public void addSpecialization(String taintInputName, StringSpecializationInfo info){
172172
if(!ExecutionTracer.getTaintType(taintInputName).isTainted()){
173-
throw new IllegalArgumentException("No valid input name: " + taintInputName);
173+
//this can happen in E2E where libraries used by "core" are instrumented (eg Kotlin)
174+
SimpleLogger.error("No valid taint input name for specialization: " + taintInputName);
175+
//throw new IllegalArgumentException();
176+
return;
174177
}
175178
Objects.requireNonNull(info);
176179

core-parent/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515

1616
<properties>
1717
<!-- upgrading to 1.0.68 breaks Spring... TODO would need try upgrading in own branch -->
18-
<swagger.parser-v2.version>1.0.61</swagger.parser-v2.version>
18+
<swagger.parser-v2.version>1.0.64</swagger.parser-v2.version>
1919
<!-- upgrading to 2.1.18 breaks Spring... TODO would need try upgrading in own branch -->
20-
<swagger.parser-v3.version>2.1.8</swagger.parser-v3.version>
20+
<swagger.parser-v3.version>2.1.14</swagger.parser-v3.version>
2121
<swagger.annotations.version>2.2.7</swagger.annotations.version>
2222
</properties>
2323

core-tests/integration-tests/core-it/src/test/kotlin/org/evomaster/core/problem/rest/SamplerVerifierTest.kt

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ import org.evomaster.client.java.controller.api.dto.problem.param.DerivedParamCh
1313
import org.evomaster.client.java.controller.api.dto.problem.rpc.ScheduleTaskInvocationsDto
1414
import org.evomaster.client.java.controller.api.dto.problem.rpc.ScheduleTaskInvocationsResult
1515
import org.evomaster.core.BaseModule
16+
import org.evomaster.core.Main
1617
import org.evomaster.core.problem.rest.schema.RestSchema
1718
import org.evomaster.core.problem.rest.service.module.BlackBoxRestModule
1819
import org.evomaster.core.problem.rest.service.module.ResourceRestModule
19-
import org.evomaster.core.problem.rest.service.sampler.ResourceSampler
20+
import org.evomaster.core.problem.rest.service.sampler.AbstractRestSampler
2021
import org.evomaster.core.remote.SutProblemException
2122
import org.evomaster.core.remote.service.RemoteController
2223
import org.evomaster.core.search.Individual
@@ -28,10 +29,17 @@ import java.lang.reflect.InvocationTargetException
2829
import java.time.Duration
2930
import kotlin.io.path.Path
3031
import kotlin.sequences.filter
32+
import kotlin.text.contains
3133

3234

3335
class SamplerVerifierTest {
3436

37+
companion object {
38+
init {
39+
Main.applyGlobalJVMSettings()
40+
}
41+
}
42+
3543

3644
@Test
3745
fun testBase() {
@@ -47,7 +55,7 @@ class SamplerVerifierTest {
4755

4856
val injector = getInjector(sutInfo, controllerInfo, false)
4957

50-
val sampler = injector.getInstance(ResourceSampler::class.java)
58+
val sampler = injector.getInstance(AbstractRestSampler::class.java)
5159

5260
sampler.sample() //should not crash
5361
}
@@ -64,11 +72,8 @@ class SamplerVerifierTest {
6472
)
6573
assertTrue(tests.isNotEmpty())
6674
return tests
67-
//FIXME once handling performance issues
68-
.filter { !it.displayName.contains("adyen") }
6975
}
7076

71-
@Disabled("Performance issue")
7277
@TestFactory
7378
fun testSamplingFromAllSchemasUnderCoreResourcesBlackBox(): Collection<DynamicTest>{
7479
val tests = sampleFromSchemasAndCheckInvariants(
@@ -81,8 +86,6 @@ class SamplerVerifierTest {
8186
}
8287

8388

84-
//FIXME need to put back, and investigate performance bug
85-
@Disabled("Major issues with timeouts. Even before, took more than 1 hour. Need refactoring. Maven was not showing the failures (likely bug in Surefire)")
8689
@TestFactory
8790
fun testSamplingFromAPIsGuru(): Collection<DynamicTest>{
8891
val tests = sampleFromSchemasAndCheckInvariants(
@@ -100,11 +103,22 @@ class SamplerVerifierTest {
100103
blackBox: Boolean
101104
): Collection<DynamicTest> {
102105

106+
/*
107+
In theory, we should not have such a high timeout for this kind of tests.
108+
On local machine, all those analyses take at most 20s per test.
109+
Maybe performance can be improved, but, considering some files are MBs, it is not
110+
so unexpected. And it happens only for very large files.
111+
Problem though is that CI is much SLOWER, and tests do timeout.
112+
So that is why we have such high timeout, it is for CI.
113+
Still, if it starts to fail there, then we really need to look into performance issues.
114+
*/
115+
val timeout = 60L
116+
103117
return scanForSchemas(relativePath, resourceFolder)
104118
.sorted().map {
105119
DynamicTest.dynamicTest(it) {
106120
System.gc()
107-
assertTimeoutPreemptively(Duration.ofSeconds(30), it) {
121+
assertTimeoutPreemptively(Duration.ofSeconds(timeout), it) {
108122
runInvariantCheck(it, 100, blackBox)
109123
}
110124
}
@@ -121,16 +135,15 @@ class SamplerVerifierTest {
121135
.filter { it.isFile }
122136
.filter { !skipSchema(it.path) }
123137
.map {
124-
// val s = it.path.replace("\\", "/")
125-
// .replace(relativePath, resourceFolder)
126138
val s = Path(it.absolutePath).toAbsolutePath().normalize().toString()
127139
s
128140
}.toList()
129141
}
130142

131143
private fun skipSchema(path: String) : Boolean {
132-
return skipDueToOldChecks(path) ||
133-
skipDueToMissingPath(path)
144+
return skipDueToOldChecks(path)
145+
|| skipDueToIssuesStillToInvestigate(path)
146+
|| skipDueToMissingPath(path)
134147
|| skipDueToHashTag(path)
135148
|| skipDueToQuestionMarkInPath(path)
136149
|| skipDueToMissingReference(path)
@@ -143,6 +156,29 @@ class SamplerVerifierTest {
143156
|| skipDueToInvalidGenes(path)
144157
}
145158

159+
private fun skipDueToIssuesStillToInvestigate(path: String) : Boolean {
160+
val toSkip = listOf(
161+
"api.video/1/openapi.yaml",
162+
"atlassian.com/jira/1001.0.0-SNAPSHOT/openapi.yaml",
163+
"cloud-elements.com/ecwid/api-v2/swagger.yaml",
164+
"github.com/api.github.com/1.1.4/openapi.yaml",
165+
"googleapis.com/discovery/v1/openapi.yaml",
166+
"here.com/positioning/2.1.1/openapi.yaml",
167+
"maif.local/otoroshi/1.5.0-dev/openapi.yaml",
168+
"mashape.com/geodb/1.0.0/swagger.yaml",
169+
"microsoft.com/cognitiveservices-Training/1.2/openapi.yaml",
170+
"microsoft.com/cognitiveservices-Training/2.0/openapi.yaml",
171+
"microsoft.com/cognitiveservices-Training/2.1/openapi.yaml",
172+
"microsoft.com/cognitiveservices-Training/2.2/openapi.yaml",
173+
"microsoft.com/cognitiveservices-Training/3.0/openapi.yaml",
174+
"microsoft.com/cognitiveservices-Training/3.1/openapi.yaml",
175+
"neutrinoapi.net/3.5.0/openapi.yaml",
176+
"openbankingproject.ch/1.3.8_2020-12-14 - Swiss edition 1.3.8.1-CH/openapi.yaml"
177+
)
178+
179+
return toSkip.any { path.contains(it) }
180+
}
181+
146182
private fun skipDueToOldChecks(path: String) : Boolean {
147183
return path.endsWith("features_service_null.json") //issue with parser
148184
|| path.endsWith("trace_v2.json") // no actions are parsed
@@ -244,7 +280,7 @@ class SamplerVerifierTest {
244280
|| (contains("visualstudio.com") && contains("v1"))
245281
|| (contains("youneedabudget.com") && contains("1.0.0"))
246282
|| (contains("zenoti.com") && contains("1.0.0")) // No actions for schema
247-
|| (contains("zoom.us") && contains("2.0.0")) // The incoming YAML document exceeds the limit: 3145728 code points.
283+
// || (contains("zoom.us") && contains("2.0.0")) // The incoming YAML document exceeds the limit: 3145728 code points.
248284
|| (contains("zuora.com") && contains("2021-08-20")) //The incoming YAML document exceeds the limit: 3145728 code points.
249285
}
250286
}
@@ -381,7 +417,7 @@ class SamplerVerifierTest {
381417
throw e
382418
}
383419

384-
val sampler = injector.getInstance(ResourceSampler::class.java)
420+
val sampler = injector.getInstance(AbstractRestSampler::class.java)
385421

386422
if(sampler.numberOfDistinctActions() == 0){
387423
throw IllegalStateException("No actions for schema")

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ package org.evomaster.core
33
import com.google.inject.AbstractModule
44
import com.google.inject.Provides
55
import com.google.inject.Singleton
6-
import org.evomaster.core.output.service.NoTestCaseWriter
76
import org.evomaster.core.output.service.PartialOracles
8-
import org.evomaster.core.output.service.TestCaseWriter
9-
import org.evomaster.core.output.service.TestSuiteWriter
107
import org.evomaster.core.search.service.mutator.genemutation.ArchiveImpactSelector
118
import org.evomaster.core.search.service.*
129
import org.evomaster.core.search.service.monitor.SearchProcessMonitor

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,26 @@ import kotlin.system.exitProcess
5454
class Main {
5555
companion object {
5656

57+
/**
58+
* Anything that impact whole JVM, needs to be done here, and called as first step in the main.
59+
* Note: this is done as a function because tests will usually not call Main, and might rely
60+
* on those settings for their behavior
61+
*/
62+
@JvmStatic
63+
fun applyGlobalJVMSettings(){
64+
Locale.setDefault(Locale.ENGLISH)
65+
//otherwise parser will crash on large OpenAPI schemas
66+
System.setProperty("maxYamlCodePoints", "" + (50 * 1024 * 1024))
67+
}
68+
5769
/**
5870
* Main entry point of the EvoMaster application
5971
*/
6072
@JvmStatic
6173
fun main(args: Array<String>) {
6274

6375
try {
64-
Locale.setDefault(Locale.ENGLISH)
76+
applyGlobalJVMSettings()
6577

6678
printLogo()
6779
printVersion()

core/src/main/kotlin/org/evomaster/core/problem/rest/schema/OpenApiAccess.kt

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,29 @@ object OpenApiAccess {
3131

3232
var parseResults: SwaggerParseResult? = null
3333

34+
val messages = mutableSetOf<String>()
35+
3436
for (extension in OpenAPIV3Parser.getExtensions()) {
3537
parseResults = try {
3638
extension.readContents(schemaText, null, null)
3739
} catch (e: Exception) {
3840
throw SutProblemException("Failed to parse OpenApi schema: ${e.message}")
3941
}
40-
if (parseResults != null && parseResults.openAPI != null) {
41-
break
42+
if (parseResults != null){
43+
if(parseResults.openAPI != null) {
44+
//all good
45+
break
46+
} else {
47+
//we might try another parser... but still shouldn't lose info of attempted parsers
48+
messages.addAll(parseResults.messages.map {
49+
extension.javaClass.simpleName + " -> " + it + "\n"
50+
})
51+
}
4252
}
4353
}
4454

4555
val schema = parseResults!!.openAPI
46-
?: throw SutProblemException("Failed to parse OpenApi schema: " + parseResults.messages.joinToString("\n"))
56+
?: throw SutProblemException("Failed to parse OpenApi schema:\n" + messages.joinToString(""))
4757

4858
if(parseResults.messages.isNotEmpty()){
4959
LoggingUtil.getInfoLogger().warn(

core/src/main/kotlin/org/evomaster/core/problem/rest/schema/RestSchema.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ package org.evomaster.core.problem.rest.schema
33
import com.fasterxml.jackson.databind.JsonNode
44
import com.fasterxml.jackson.databind.ObjectMapper
55
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
6+
import com.fasterxml.jackson.dataformat.yaml.YAMLFactoryBuilder
67
import org.evomaster.core.remote.SutProblemException
8+
import org.yaml.snakeyaml.LoaderOptions
79

810

911
/**
@@ -62,7 +64,16 @@ class RestSchema(
6264

6365
//https://swagger.io/docs/specification/v3_0/using-ref/
6466

65-
val mapper = ObjectMapper(YAMLFactory())
67+
// snakeyaml has default limits on size, which are very low
68+
val yaml = YAMLFactoryBuilder(YAMLFactory())
69+
.loaderOptions(LoaderOptions().apply {
70+
codePointLimit = 50 * 1024 * 1024 // 50MB
71+
maxAliasesForCollections = 1000
72+
nestingDepthLimit = 100
73+
})
74+
.build()
75+
76+
val mapper = ObjectMapper(yaml)
6677
val tree = mapper.readTree(schema.schemaRaw)
6778
val refs = findAllSRef(tree)
6879

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import org.evomaster.core.problem.rest.service.sampler.AbstractRestSampler
77
import org.evomaster.core.problem.rest.service.fitness.BlackBoxRestFitness
88
import org.evomaster.core.problem.rest.service.sampler.RestSampler
99
import org.evomaster.core.problem.enterprise.service.EnterpriseSampler
10-
import org.evomaster.core.problem.rest.service.sampler.ResourceSampler
1110
import org.evomaster.core.remote.service.RemoteController
1211
import org.evomaster.core.remote.service.RemoteControllerImplementation
1312
import org.evomaster.core.search.service.FitnessFunction
@@ -22,7 +21,7 @@ class BlackBoxRestModule(
2221
super.configure()
2322

2423
bind(object : TypeLiteral<EnterpriseSampler<RestIndividual>>() {})
25-
.to(ResourceSampler::class.java)
24+
.to(RestSampler::class.java)
2625
.asEagerSingleton()
2726
bind(object : TypeLiteral<Sampler<RestIndividual>>() {})
2827
.to(RestSampler::class.java)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ class RestSampler : AbstractRestSampler(){
274274
if (created && !get.path.isLastElementAParameter()) {
275275

276276
val lastPost = test[test.size - 2]
277-
Lazy.assert{lastPost.verb == HttpVerb.POST}
277+
Lazy.assert{lastPost.verb == HttpVerb.POST || lastPost.verb == HttpVerb.PUT}
278278

279279
val available = getMaxTestSizeDuringSampler() - test.size
280280

0 commit comments

Comments
 (0)