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
9 changes: 9 additions & 0 deletions core/src/main/kotlin/org/evomaster/core/EMConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -1101,6 +1101,13 @@ class EMConfig {
" If no tag is specified here, then such filter is not applied.")
var endpointTagFilter: String? = null

@Important(5.2)
@Cfg("Comma-separated list of endpoints for excluding endpoints." +
" This is useful for excluding endpoints that are not relevant for testing, " +
" such as those used for health checks or metrics. If no such endpoint is specified, " +
" then no endpoints are excluded from the search.")
var endpointExclude: String? = null

@Important(6.0)
@Cfg("Host name or IP address of where the SUT EvoMaster Controller Driver is listening on." +
" This option is only needed for white-box testing.")
Expand Down Expand Up @@ -2726,5 +2733,7 @@ class EMConfig {

fun getTagFilters() = endpointTagFilter?.split(",")?.map { it.trim() } ?: listOf()

fun getExcludeEndpoints() = endpointExclude?.split(",")?.map { it.trim() } ?: listOf()

fun isEnabledAIModelForResponseClassification() = aiModelForResponseClassification != AIResponseClassifierModel.NONE
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ object EndpointFilter {

if(config.endpointFocus.isNullOrBlank()
&& config.endpointPrefix.isNullOrBlank()
&& config.endpointTagFilter.isNullOrBlank()){
&& config.endpointTagFilter.isNullOrBlank()
&& config.endpointExclude.isNullOrBlank()){
return listOf()
}

Expand All @@ -39,6 +40,10 @@ object EndpointFilter {
Endpoint.validatePrefix(config.endpointPrefix!!, swagger)
}

if(! config.endpointExclude.isNullOrBlank()){
Endpoint.validateExclude(config.getExcludeEndpoints(), swagger)
}

val all = Endpoint.fromOpenApi(swagger)

val x = if(config.endpointFocus != null) {
Expand All @@ -56,9 +61,18 @@ object EndpointFilter {
listOf()
}

val excludes = config.getExcludeEndpoints()

val z = if(excludes.isNotEmpty()){
all.filter { e -> excludes.contains(e.path.toString()) }
} else {
listOf()
}

return mutableSetOf<Endpoint>().apply {
addAll(x)
addAll(y)
addAll(z)
}.toList()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ class Endpoint(
throw ConfigProblemException("The focus endpoint '$focus' does not match any endpoint in the schema")
}
}
fun validateExclude(excludeEndpoints: List<String>, schema: OpenAPI){
excludeEndpoints.forEach { ex ->
if(schema.paths.none { it.key == ex }){
throw ConfigProblemException("The focus endpoint '$ex' does not match any endpoint in the schema")
}
}
}

}

fun getTags(schema: OpenAPI) : List<String>{
Expand Down
1 change: 1 addition & 0 deletions docs/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ There are 3 types of options:
|`header2`| __String__. See documentation of _header0_. *Constraints*: `regex (.+:.+)\|(^$)`. *Default value*: `""`.|
|`endpointFocus`| __String__. Concentrate search on only one single REST endpoint. *Default value*: `null`.|
|`endpointPrefix`| __String__. Concentrate search on a set of REST endpoints defined by a common prefix. *Default value*: `null`.|
|`endpointExclude`| __String__. Comma-separated list of endpoints for excluding endpoints. This is useful for excluding endpoints that are not relevant for testing, such as those used for health checks or metrics. If no such endpoint is specified, then no endpoints are excluded from the search. *Default value*: `null`.|
|`endpointTagFilter`| __String__. Comma-separated list of OpenAPI/Swagger 'tags' definitions. Only the REST endpoints having at least one of such tags will be fuzzed. If no tag is specified here, then such filter is not applied. *Default value*: `null`.|
|`sutControllerHost`| __String__. Host name or IP address of where the SUT EvoMaster Controller Driver is listening on. This option is only needed for white-box testing. *Default value*: `localhost`.|
|`sutControllerPort`| __Int__. TCP port of where the SUT EvoMaster Controller Driver is listening on. This option is only needed for white-box testing. *Constraints*: `min=0.0, max=65535.0`. *Default value*: `40100`.|
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.foo.rest.examples.spring.endpointexclude;

import com.foo.rest.examples.spring.SwaggerConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@EnableSwagger2
@SpringBootApplication(exclude = SecurityAutoConfiguration.class)
public class EndpointExcludeApplication extends SwaggerConfiguration {

public static void main(String[] args) {
SpringApplication.run(EndpointExcludeApplication.class, args);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.foo.rest.examples.spring.endpointexclude;

import io.swagger.annotations.ApiOperation;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(path = "/api/endpointexclude")
public class EndpointExcludeRest {

@ApiOperation(value="", tags = "Foo")
@RequestMapping(value = "/x", method = RequestMethod.GET)
ResponseEntity<?> getX() {
return ResponseEntity.ok().build();
}

@ApiOperation(value="", tags = "Foo")
@RequestMapping(value = "/x", method = RequestMethod.POST)
ResponseEntity<?> postX() {
return ResponseEntity.ok().build();
}

@ApiOperation(value="", tags = "Foo")
@RequestMapping(value = "/x", method = RequestMethod.PUT)
ResponseEntity<?> putX() {
return ResponseEntity.ok().build();
}


@ApiOperation(value="", tags = "Bar")
@RequestMapping(value = "/y", method = RequestMethod.GET)
ResponseEntity<?> getY() {
return ResponseEntity.ok().build();
}

@ApiOperation(value="", tags = {"Foo", "Bar"})
@RequestMapping(value = "/y/z", method = RequestMethod.GET)
ResponseEntity<?> getZ() {
return ResponseEntity.ok().build();
}

@ApiOperation(value="", tags = {"Foo", "Bar"})
@RequestMapping(value = "/y/z/k", method = RequestMethod.GET)
ResponseEntity<?> getK() {
return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.foo.rest.examples.spring.endpointexclude;

import com.foo.rest.examples.spring.SpringController;
import org.evomaster.client.java.controller.problem.ProblemInfo;
import org.evomaster.client.java.controller.problem.RestProblem;

import java.util.Arrays;

public class EndpointExcludeController extends SpringController {

public EndpointExcludeController(){
super(EndpointExcludeApplication.class);
}

@Override
public ProblemInfo getProblemInfo() {

return new RestProblem(
"http://localhost:" + getSutPort() + "/v2/api-docs",
null
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.evomaster.e2etests.spring.examples.endpointexclude;

import com.foo.rest.examples.spring.endpointexclude.EndpointExcludeController;
import org.evomaster.core.problem.rest.data.HttpVerb;
import org.evomaster.core.problem.rest.data.RestIndividual;
import org.evomaster.core.search.Solution;
import org.evomaster.e2etests.spring.examples.SpringTestBase;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

public class EndpointExcludeEMTest extends SpringTestBase {

@BeforeAll
public static void initClass() throws Exception {

SpringTestBase.initClass(new EndpointExcludeController());
}

@Test
public void testRunEM() throws Throwable {

runTestHandlingFlakyAndCompilation(
"EndpointExcludeEM",
"org.foo.EndpointExcludeEM",
50,
(args) -> {

args.add("--endpointExclude");
args.add("/api/endpointexclude/x,/api/endpointexclude/y");

Solution<RestIndividual> solution = initAndRun(args);

assertFalse(solution.getIndividuals().isEmpty());

assertHasAtLeastOne(solution, HttpVerb.GET, 200, "/api/endpointexclude/y/z", null);
assertNone(solution, HttpVerb.GET, 200, "/api/endpointexclude/x", null);
assertNone(solution, HttpVerb.GET, 200, "/api/endpointexclude/y", null);
});
}
}
Loading