Skip to content

Commit

Permalink
Merge pull request #936 from EMResearch/scaffolding-it
Browse files Browse the repository at this point in the history
working on new integration tests for REST
  • Loading branch information
arcuri82 authored Mar 27, 2024
2 parents 229e68a + 9755c39 commit b146420
Show file tree
Hide file tree
Showing 31 changed files with 427 additions and 28 deletions.
23 changes: 23 additions & 0 deletions core-it/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,29 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springdoc</groupId>-->
<!-- <artifactId>springdoc-openapi-security</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-kotlin</artifactId>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency>

<dependency>
<groupId>org.evomaster</groupId>
<artifactId>evomaster-e2e-tests-utils</artifactId>
<type>test-jar</type>
<version>${project.version}</version>
</dependency>

</dependencies>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package bar.examples.it.spring.pathstatus

import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
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.RequestMapping
import org.springframework.web.bind.annotation.RestController

@SpringBootApplication(exclude = [SecurityAutoConfiguration::class])
@RequestMapping(path = ["/api/pathstatus"])
@RestController
open class PathStatusApplication {


companion object {
@JvmStatic
fun main(args: Array<String>) {
SpringApplication.run(PathStatusApplication::class.java, *args)
}
}

@GetMapping("/byStatus/{status}")
open fun getByStatus(@PathVariable status: Int) : ResponseEntity<String> {

return ResponseEntity.status(status).body("byStatus")
}

@GetMapping("/others/{x}")
open fun getOthers(@PathVariable x: Int) : ResponseEntity<String> {

return ResponseEntity.status(200).body("$x")
}



}
67 changes: 67 additions & 0 deletions core-it/src/test/kotlin/bar/examples/it/spring/SpringController.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package bar.examples.it.spring

import org.evomaster.client.java.controller.EmbeddedSutController
import org.evomaster.client.java.controller.api.dto.auth.AuthenticationDto
import org.evomaster.client.java.controller.api.dto.SutInfoDto
import org.evomaster.client.java.sql.DbSpecification
import org.evomaster.client.java.controller.problem.ProblemInfo
import org.evomaster.client.java.controller.problem.RestProblem
import org.springframework.boot.SpringApplication
import org.springframework.context.ConfigurableApplicationContext


abstract class SpringController(protected val applicationClass: Class<*>) : EmbeddedSutController() {

init {
super.setControllerPort(0)
}


protected var ctx: ConfigurableApplicationContext? = null

override fun startSut(): String {
ctx = SpringApplication.run(applicationClass, "--server.port=0")
return "http://localhost:$sutPort"
}

protected val sutPort: Int
get() = (ctx!!.environment
.propertySources["server.ports"].source as Map<*, *>)["local.server.port"] as Int

override fun isSutRunning(): Boolean {
return ctx != null && ctx!!.isRunning
}

override fun stopSut() {
ctx?.stop()
ctx?.close()
}

override fun getPackagePrefixesToCover(): String {
return "bar.foo."
}

override fun resetStateOfSUT() { //nothing to do
}

override fun getProblemInfo(): ProblemInfo {
return RestProblem(
"http://localhost:$sutPort/v3/api-docs",
null
)
}

override fun getInfoForAuthentication(): List<AuthenticationDto> {
return listOf()
}

override fun getDbSpecifications(): MutableList<DbSpecification>? {
return null
}


override fun getPreferredOutputFormat(): SutInfoDto.OutputFormat {
return SutInfoDto.OutputFormat.KOTLIN_JUNIT_5
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package bar.examples.it.spring.pathstatus

import bar.examples.it.spring.SpringController

class PathStatusController : SpringController(PathStatusApplication::class.java)
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.evomaster.core.problem.rest

import com.google.inject.Injector
import org.evomaster.core.problem.enterprise.SampleType
import org.evomaster.core.problem.rest.service.AbstractRestFitness
import org.evomaster.core.problem.rest.service.AbstractRestSampler
import org.evomaster.core.search.EvaluatedIndividual
import org.evomaster.core.search.service.SearchGlobalState
import org.evomaster.core.seeding.service.rest.PirToRest
import org.evomaster.e2etests.utils.RestTestBase
import org.junit.jupiter.api.BeforeEach

abstract class IntegrationTestRestBase : RestTestBase() {


protected lateinit var injector: Injector

@BeforeEach
fun initInjector(){
val args = listOf(
"--sutControllerPort", "" + controllerPort,
"--createConfigPathIfMissing", "false"
)
injector = init(args)
}

fun getPirToRest() = injector.getInstance(PirToRest::class.java)


fun createIndividual(actions: List<RestCallAction>): EvaluatedIndividual<RestIndividual> {

// val searchGlobalState = injector.getInstance(SearchGlobalState::class.java)

// val ind = RestIndividual(actions.toMutableList(), SampleType.SEEDED)
// ind.doGlobalInitialize(searchGlobalState)

val sampler = injector.getInstance(AbstractRestSampler::class.java)
/*
the method `createIndividual` can be overridden
in this case, the sampler is an instance of ResourceSampler,
then check its implementation in ResourceSampler.createIndividual(...)
*/
val ind = sampler.createIndividual(SampleType.SEEDED, actions.toMutableList())

val ff = injector.getInstance(AbstractRestFitness::class.java)
val ei = ff.calculateCoverage(ind)!!

return ei
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.evomaster.core.problem.rest.selectorutils

import bar.examples.it.spring.pathstatus.PathStatusController
import org.evomaster.core.problem.rest.HttpVerb
import org.evomaster.core.problem.rest.IntegrationTestRestBase
import org.evomaster.core.problem.rest.RestIndividualSelectorUtils
import org.evomaster.core.problem.rest.RestPath
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test

class RestIndividualSelectorUtilsPathStatusTest : IntegrationTestRestBase(){

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


@Test
fun testPathStatus(){

val pirTest = getPirToRest()

val byStatus = RestPath("/api/pathstatus/byStatus/{status}")
val others = RestPath("/api/pathstatus/others/{x}")

val s200 = pirTest.fromVerbPath("get", "/api/pathstatus/byStatus/200")!!
val s400 = pirTest.fromVerbPath("get", "/api/pathstatus/byStatus/400")!!
val o200 = pirTest.fromVerbPath("get", "/api/pathstatus/others/200")!!
val o500 = pirTest.fromVerbPath("get", "/api/pathstatus/others/500")!!

val x0 = createIndividual(listOf(s200))
val x1 = createIndividual(listOf(s400))
val x2 = createIndividual(listOf(o200))
val x3 = createIndividual(listOf(o500))

val individuals = listOf(x0,x1,x2,x3)

val r0 = RestIndividualSelectorUtils.findIndividuals(individuals, HttpVerb.GET, byStatus, 200)
assertEquals(1, r0.size)

val r1 = RestIndividualSelectorUtils.findIndividuals(individuals, HttpVerb.GET, byStatus, 500)
assertEquals(0, r1.size)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ abstract class Param(
val genes : MutableList<Gene>
) : StructuralElement(genes){

//TODO need refactoring
//TODO need refactoring. eg shared abstract class for cases in which only 1 gene for sure
@Deprecated("Assumes there is only 1 gene")
val gene : Gene = genes[0]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ import kotlin.math.max
*
* @property trackOperator indicates which operator create this individual.
* @property index indicates when the individual is created, ie, using num of evaluated individual.
*
*
* FIXME: why having to use AbstractRestSampler.createIndividual() instead of having such code here in constructor???
*/
class RestIndividual(
sampleType: SampleType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ object RestIndividualSelectorUtils {
return null
}

fun findIndividuals(
fun old_findIndividuals(
individuals: List<EvaluatedIndividual<RestIndividual>>,
verb: HttpVerb,
statusGroup: String
Expand Down Expand Up @@ -88,9 +88,11 @@ object RestIndividualSelectorUtils {
/*
Find individuals containing a certain action and STATUS
*/
fun getIndividualsWithActionAndStatus(individualsInSolution: List<EvaluatedIndividual<RestIndividual>>,
verb: HttpVerb, statusCode: Int)
:List<EvaluatedIndividual<RestIndividual>> {
fun getIndividualsWithActionAndStatus(
individualsInSolution: List<EvaluatedIndividual<RestIndividual>>,
verb: HttpVerb,
statusCode: Int
):List<EvaluatedIndividual<RestIndividual>> {

val individualsList = mutableListOf<EvaluatedIndividual<RestIndividual>>()

Expand Down Expand Up @@ -143,7 +145,7 @@ object RestIndividualSelectorUtils {
return foundRestAction
}

fun getIndividualsWithActionAndStatus(
fun findIndividuals(
individuals: List<EvaluatedIndividual<RestIndividual>>,
verb: HttpVerb,
path: RestPath,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import java.util.regex.Pattern
* the set of default actions (i.e., actions representing single calls to each API
* operation) and the Swagger specification.
*/
@Deprecated("Code here will be replaced with intermediate representation. See new 'seeding' package")
abstract class AbstractParser(
protected val defaultRestCallActions: List<RestCallAction>,
protected val swagger: OpenAPI
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package org.evomaster.core.problem.rest.seeding

import org.evomaster.core.problem.rest.RestCallAction


@Deprecated("Code here will be replaced with intermediate representation. See new 'seeding' package")
interface Parser {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import java.lang.IllegalStateException
import java.net.URLDecoder
import java.nio.charset.StandardCharsets

@Deprecated("Code here will be replaced with intermediate representation. See new 'seeding' package")
class PostmanParser(
defaultRestCallActions: List<RestCallAction>,
swagger: OpenAPI
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import javax.ws.rs.core.NewCookie
import javax.ws.rs.core.Response


abstract class AbstractRestFitness<T> : HttpWsFitness<T>() where T : Individual {
abstract class AbstractRestFitness : HttpWsFitness<RestIndividual>() {

// TODO: This will moved under ApiWsFitness once RPC and GraphQL support is completed
@Inject
Expand Down Expand Up @@ -760,7 +760,7 @@ abstract class AbstractRestFitness<T> : HttpWsFitness<T>() where T : Individual
return null
}

val dto = updateFitnessAfterEvaluation(targets, allCovered, individual as T, fv)
val dto = updateFitnessAfterEvaluation(targets, allCovered, individual, fv)
?: return null

handleExtra(dto, fv)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,9 @@ abstract class AbstractRestSampler : HttpWsSampler<RestIndividual>() {
/**
* @return a created individual with specified actions, i.e., [restCalls].
* All actions must have been already initialized
*
*
* FIXME: why this function instead of dealing with this directly in the constructor of RestIndividual???
*/
open fun createIndividual(sampleType: SampleType, restCalls: MutableList<RestCallAction>): RestIndividual {
if(restCalls.any { !it.isInitialized() }){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import org.evomaster.core.search.service.Archive
import org.evomaster.core.search.service.FitnessFunction
import org.evomaster.core.search.service.Minimizer
import org.evomaster.core.search.service.Sampler
import org.evomaster.core.seeding.service.rest.PirToRest

class BlackBoxRestModule(
val usingRemoteController: Boolean
Expand Down Expand Up @@ -69,5 +70,9 @@ class BlackBoxRestModule(

bind(SecurityRest::class.java)
.asEagerSingleton()

bind(PirToRest::class.java)
.asEagerSingleton()

}
}
Loading

0 comments on commit b146420

Please sign in to comment.