Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions core-parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@
<artifactId>swagger-request-validator-core</artifactId>
<version>2.44.9</version>
</dependency>
<dependency>
<groupId>com.webfuzzing</groupId>
<artifactId>overlay-jvm</artifactId>
<version>0.1.1</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.foo.rest.examples.spring.openapi.v3.overlay

import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration

@SpringBootApplication(exclude = [SecurityAutoConfiguration::class])
open class OverlayApplication {

companion object {
@JvmStatic
fun main(args: Array<String>) {
SpringApplication.run(OverlayApplication::class.java, *args)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.foo.rest.examples.spring.openapi.v3.overlay

import com.foo.rest.examples.spring.openapi.v3.charescaperegex.CharEscapeRegexDto
import com.foo.rest.examples.spring.openapi.v3.stringlength.StringLengthDto
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import java.util.regex.Pattern
import javax.validation.Valid
import javax.ws.rs.QueryParam

@RestController
@RequestMapping(path = ["/api/overlay"])
open class OverlayRest {

@GetMapping
open fun get( @QueryParam("x") x: String, @QueryParam("y") y: String) : ResponseEntity<String>{

return ResponseEntity.ok("x=$x , y=$y")
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
overlay: 1.1.0
info:
title: Add example to x parameter
version: 1.0.0
actions:
- target: $.paths.['/api/overlay'].get.parameters[?(@.name == 'y')]
update:
examples:
foo:
value: "Some Y value like 777"
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
overlay: 1.1.0
info:
title: Add example to x parameter
version: 1.0.0
actions:
- target: $.paths.['/api/overlay'].get.parameters[?(@.name == 'x')]
update:
examples:
foo:
value: "Some X value like 1234"
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"overlay": "1.1.0",
"info": {
"title": "Add example to non-existing z parameter",
"version": "1.0.0"
},
"actions": [
{
"target": "$.paths.['/api/overlay'].get.parameters[?(@.name == 'z')]",
"update": {
"examples": {
"foo": {
"value": "Some X value like 1234"
}
}
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.foo.rest.examples.spring.openapi.v3.overlay

import com.foo.rest.examples.spring.openapi.v3.SpringController

class OverlayController : SpringController(OverlayApplication::class.java)
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package org.evomaster.e2etests.spring.openapi.v3.overlay

import com.foo.rest.examples.spring.openapi.v3.overlay.OverlayController
import com.foo.rest.examples.spring.openapi.v3.stringlength.StringLengthController
import org.evomaster.core.config.ConfigProblemException
import org.evomaster.core.problem.rest.data.HttpVerb
import org.evomaster.e2etests.spring.openapi.v3.SpringTestBase
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows

class OverlayEMTest : SpringTestBase(){

companion object {
@BeforeAll
@JvmStatic
fun init() {
initClass(OverlayController())
}
}

//these should be kept in sink with what written in the Overlay files
private val X = "Some X value like 1234"
private val Y = "Some Y value like 777"

@Test
fun testRunEM_Overlay_None() {

runTestHandlingFlakyAndCompilation(
"Overlay_None",
100
) { args: MutableList<String> ->

val solution = initAndRun(args)

Assertions.assertTrue(solution.individuals.size >= 1)
assertHasAtLeastOne(solution, HttpVerb.GET, 200, "/api/overlay", null)
assertNone(solution, HttpVerb.GET, 200, "/api/overlay", X)
assertNone(solution, HttpVerb.GET, 200, "/api/overlay", Y)
}
}


@Test
fun testRunEM_Overlay_X() {

runTestHandlingFlakyAndCompilation(
"Overlay_X",
100
) { args: MutableList<String> ->

setOption(args, "overlay", "src/main/resources/overlay/x.yaml")

val solution = initAndRun(args)

Assertions.assertTrue(solution.individuals.size >= 1)
assertHasAtLeastOne(solution, HttpVerb.GET, 200, "/api/overlay", X)
assertNone(solution, HttpVerb.GET, 200, "/api/overlay", Y)
}
}

@Test
fun testRunEM_Overlay_Y_BB() {

runTestHandlingFlakyAndCompilation(
"Overlay_Y_BB",
100
) { args: MutableList<String> ->

setOption(args, "overlay", "src/main/resources/overlay/subfolder/y.yaml")
setOption(args, "blackBox", "true")
setOption(args, "bbTargetUrl", baseUrlOfSut)
setOption(args, "bbSwaggerUrl", "$baseUrlOfSut/v3/api-docs")

val solution = initAndRun(args)

Assertions.assertTrue(solution.individuals.size >= 1)
assertNone(solution, HttpVerb.GET, 200, "/api/overlay", X)
assertHasAtLeastOne(solution, HttpVerb.GET, 200, "/api/overlay", Y)
}
}


@Test
fun testRunEM_Overlay_Z_fail() {

runTestHandlingFlakyAndCompilation(
"Overlay_Z_fail",
100
) { args: MutableList<String> ->

setOption(args, "overlay", "src/main/resources/overlay/z.json")
//default behavior must be non-lenient

//z does not exist
assertThrows<ConfigProblemException> { initAndRun(args) }
}
}

@Test
fun testRunEM_Overlay_Z_lenient() {

runTestHandlingFlakyAndCompilation(
"Overlay_Z_lenient",
100
) { args: MutableList<String> ->

setOption(args, "overlay", "src/main/resources/overlay/z.json")
setOption(args, "overlayLenient", "true")

//z does not exist... but, when lenient, shouldn't fail
val solution = initAndRun(args)

Assertions.assertTrue(solution.individuals.size >= 1)
assertHasAtLeastOne(solution, HttpVerb.GET, 200, "/api/overlay", null)
assertNone(solution, HttpVerb.GET, 200, "/api/overlay", X)
assertNone(solution, HttpVerb.GET, 200, "/api/overlay", Y)
}
}

@Test
fun testRunEM_Overlay_folder() {

runTestHandlingFlakyAndCompilation(
"Overlay_folder",
100
) { args: MutableList<String> ->

setOption(args, "overlay", "src/main/resources/overlay")
//by default, z.json will be picked, and so failed because non-lenient

//z does not exist
assertThrows<ConfigProblemException> { initAndRun(args) }
}
}


@Test
fun testRunEM_Overlay_folder_filtered() {

runTestHandlingFlakyAndCompilation(
"Overlay_folder_filtered",
100
) { args: MutableList<String> ->

setOption(args, "overlay", "src/main/resources/overlay")
//make sure to not pick-up z.json
setOption(args, "overlayFileSuffixes", ".yaml")

val solution = initAndRun(args)

Assertions.assertTrue(solution.individuals.size >= 1)
assertHasAtLeastOne(solution, HttpVerb.GET, 200, "/api/overlay", X)
assertHasAtLeastOne(solution, HttpVerb.GET, 200, "/api/overlay", Y)
}
}


}
4 changes: 4 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
<groupId>com.webfuzzing</groupId>
<artifactId>commons</artifactId>
</dependency>
<dependency>
<groupId>com.webfuzzing</groupId>
<artifactId>overlay-jvm</artifactId>
</dependency>


<dependency>
Expand Down
58 changes: 55 additions & 3 deletions core/src/main/kotlin/org/evomaster/core/EMConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,6 @@ class EMConfig {
throw ConfigProblemException("'bbTargetUrl' should be set only in black-box mode")
}

// ONUR, this line is changed since it did not compile in the previous case.
if (!endpointFocus.isNullOrBlank() && !endpointPrefix.isNullOrBlank()) {
throw ConfigProblemException("both 'endpointFocus' and 'endpointPrefix' are set")
}
Expand Down Expand Up @@ -913,14 +912,34 @@ class EMConfig {

if (Files.exists(path) && !Files.isWritable(path)) {
throw ConfigProblemException("Parameter '${m.name}' refers to a file that already" +
" exists, but that cannot be written/replace to: $path")
" exists, but that cannot be written/replaced to: $path")
}
if (Files.exists(path) && Files.isDirectory(path)) {
throw ConfigProblemException("Parameter '${m.name}' refers to a file that is instead an" +
" existing folder: $path")
}
}
}

m.annotations.find { it is ExistingPath }?.also{
val ep = it as ExistingPath
if(! (ep.canBeBlank && parameterValue.isBlank())){
val path = try {
Paths.get(parameterValue).toAbsolutePath()
} catch (e: InvalidPathException) {
throw ConfigProblemException("Parameter '${m.name}' is not a valid FS path: ${e.message}")
}

if (!Files.exists(path)){
throw ConfigProblemException("File/folder for '${m.name}' does not exist: $path")
}

if( ep.shouldBeWritable && !Files.isWritable(path)){
throw ConfigProblemException("Parameter '${m.name}' refers to a file that" +
" exists, but it cannot be written/replaced to: $path")
}
}
}
}


Expand Down Expand Up @@ -1052,7 +1071,7 @@ class EMConfig {


/**
* This represent one of the main properties to set in EvoMaster.
* This represents one of the main properties to set in EvoMaster.
* Those are the ones most likely going to be set by practitioners.
* Note: most of the other properties are mainly for experiments
*/
Expand All @@ -1074,6 +1093,13 @@ class EMConfig {
@MustBeDocumented
annotation class FilePath(val canBeBlank: Boolean = false)

/**
* Either a file or a folder, that MUST already exist and can be read.
*/
@Target(AnnotationTarget.PROPERTY)
@MustBeDocumented
annotation class ExistingPath(val canBeBlank: Boolean = false, val shouldBeWritable: Boolean = false)


//------------------------------------------------------------------------

Expand Down Expand Up @@ -3049,6 +3075,32 @@ class EMConfig {
" path element of the URL will not change).")
var overrideAuthExternalEndpointURL : String? = null

@Experimental
@ExistingPath(true,false)
@Cfg("Specify an OAI Overlay file path, or a folder containing those." +
" In this latter case, Overlay files will be searched recursively in the nested folder, matching" +
" a given list of configurable suffixes." +
" Each Overlay will be applied to the target OpenAPI schema." +
" If more than one Overlay file is applied, no specific ordering of transformations is enforced.")
var overlay = ""

@Experimental
@Cfg("Comma ',' separated list of file name suffixes." +
" When scanning a folder for OAI Overlay files, any file with name matching any one of these" +
" suffixes will be loaded and applied." +
" For example, '.json' could be used to match all JSON files." +
" If the folder contains also other types of files with same extension, you might need to define" +
" some naming convention, and then use suffixes based on it, e.g., '-overlay.yaml' to match" +
" all YAML files whose name ends in 'overlay', like 'example-overlay.yaml'.")
var overlayFileSuffixes = ".json,.yaml,.yml"

@Experimental
@Cfg("When applying Overlay transformations, by default EvoMaster will crash immediately" +
" if there is any issue with the transformations, e.g., if some transformations are not applied" +
" because the JSON Path selectors found no applicable node in the OpenAPI schema." +
" This option can be used to override such behavior, and let the fuzzing go on without" +
" applying any overlay.")
var overlayLenient = false

fun getProbabilityUseDataPool() : Double{
return if(blackBox){
Expand Down
Loading
Loading