Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
ed80b98
ArazzoSampler v1 - Only Sampler
daniellopera15 Jun 21, 2026
0a157cb
Sampler with test - Not Working
daniellopera15 Jun 26, 2026
8c8dfbe
Arazzo Verifier Sampler Test
daniellopera15 Jul 7, 2026
ef00cfe
Add new test in ArazzoVerifierSampletTest
daniellopera15 Jul 15, 2026
c55a13b
Fix pom version and imports
daniellopera15 Jul 15, 2026
f474d74
Add comments in tests ArazzoSamplerVerifierTest
daniellopera15 Jul 20, 2026
097b64c
Fix merge conflicts
daniellopera15 Aug 14, 2026
6b50305
Generate Markdown documentacion - Arazzo
daniellopera15 Aug 14, 2026
1b269ad
Arazzo Sampler: Review refactor v1
daniellopera15 Aug 19, 2026
48c6e94
Arazzo Sampler: Review refactor v2
daniellopera15 Aug 21, 2026
e779e61
ArazzoSampler: Review refactor v3
daniellopera15 Aug 23, 2026
3b7a033
ArazzoSampler: Review refactor v4
daniellopera15 Sep 1, 2026
c889646
Merge branch 'master' into feature/arazzo-sampler
daniellopera15 Sep 1, 2026
2fc861f
Merge remote-tracking branch 'upstream/master' into feature/arazzo-sa…
daniellopera15 Sep 5, 2026
24d3d0e
ArazzoSampler: Review refactor v5
daniellopera15 Sep 5, 2026
11e9db0
Merge branch 'feature/arazzo-sampler' of https://github.com/WebFuzzin…
daniellopera15 Sep 5, 2026
6daa628
ArazzoSampler: Review refacor v6
daniellopera15 Sep 6, 2026
d708715
ArazzoSampler: Review refactor v7
daniellopera15 Sep 9, 2026
2525dc1
ArazzoSampler: Review refactor v8
daniellopera15 Sep 9, 2026
062fd6c
Merge remote-tracking branch 'upstream/master' into feature/arazzo-sa…
daniellopera15 Sep 13, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* This model only have SuccessAction, FailureAction and Parameter.
* The references are expected to be resolved by {@link ArazzoReferenceResolver}.
*/
//TODO to rename it to ArazzoStep
public class Step {
/**
* A description of the step.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* This model only have SuccessAction, FailureAction and Parameter.
* The references are expected to be resolved by {@link ArazzoReferenceResolver}.
*/
//TODO to rename it to ArazzoWorkflow
public class Workflow {
/**
* Unique string to represent the workflow.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
package org.evomaster.core.problem.rest

import com.google.inject.AbstractModule
import com.google.inject.Injector
import com.google.inject.Provides
import com.google.inject.Singleton
import com.netflix.governator.guice.LifecycleInjector
import org.evomaster.client.java.controller.api.dto.*
import org.evomaster.client.java.controller.api.dto.database.operations.*
import org.evomaster.client.java.controller.api.dto.problem.RestProblemDto
import org.evomaster.client.java.controller.api.dto.problem.param.DeriveParamResponseDto
import org.evomaster.client.java.controller.api.dto.problem.param.DerivedParamChangeReqDto
import org.evomaster.client.java.controller.api.dto.problem.rpc.ScheduleTaskInvocationsDto
import org.evomaster.client.java.controller.api.dto.problem.rpc.ScheduleTaskInvocationsResult
import org.evomaster.core.BaseModule
import org.evomaster.core.Main
import org.evomaster.core.problem.rest.data.HttpVerb
import org.evomaster.core.problem.rest.data.RestCallAction
import org.evomaster.core.problem.rest.service.ArazzoWorkflowsService
import org.evomaster.core.problem.rest.service.module.RestModule
import org.evomaster.core.problem.rest.data.RestIndividual
import org.evomaster.core.problem.rest.service.sampler.RestSampler
import org.evomaster.core.remote.service.RemoteController
import org.evomaster.core.search.Individual
import com.webfuzzing.arazzo.models.domain.Workflow
import org.evomaster.core.search.gene.Gene
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import java.io.File

class SamplerWithArazzoVerifierTest {

companion object {
init {
Main.applyGlobalJVMSettings()
}
}

private data class TestContext(
val sampler: RestSampler,
val arazzoService: ArazzoWorkflowsService,
)

@Test
fun testSamplerWithArazzoProducesValidIndividuals() {
val context = createTestContext()

assertTrue(context.arazzoService.arazzoWorkflows.isNotEmpty(), "Arazzo workflows should be loaded at init")
assertTrue(context.sampler.numberOfDistinctActions() > 0, "OpenAPI should yield REST actions")

repeat(10) {
checkInvariant(context.sampler.sample(forceRandomSample = true))
}
}

/**
* It is a test that validates the correct formation of expected workflows from a specific Arazzo document.
* Linear workflows only
*/
@Test
fun testSamplerWithArazzoGeneratesValidIndividualWorkflows() {
val context = createTestContext()

//apply-coupon
var workflow = context.arazzoService.arazzoWorkflowsById["apply-coupon"]!!
var ind = buildIndividualFromWorkflow(context, workflow)
var actions = ind.seeAllActions().filterIsInstance<RestCallAction>()

assertEquals(listOf("findPetsByTags", "getPetCoupons", "placeOrder"), actions.map { it.operationId })
assertEquals(listOf(HttpVerb.GET, HttpVerb.GET, HttpVerb.POST), actions.map { it.verb })
assertEquals(listOf("/pet/findByTags", "/pet/{petId}/coupons", "/store/order"), actions.map { it.path.toString() })

//buy-available-pet
workflow = context.arazzoService.arazzoWorkflowsById["buy-available-pet"]!!
ind = buildIndividualFromWorkflow(context, workflow)
actions = ind.seeAllActions().filterIsInstance<RestCallAction>()

assertEquals(listOf("findPetsByStatus", "placeOrder"), actions.map { it.operationId })
assertEquals(listOf(HttpVerb.GET, HttpVerb.POST), actions.map { it.verb })
assertEquals(listOf("/pet/findByStatus", "/store/order"), actions.map { it.path.toString() })

//place-order
workflow = context.arazzoService.arazzoWorkflowsById["place-order"]!!
ind = buildIndividualFromWorkflow(context, workflow)
actions = ind.seeAllActions().filterIsInstance<RestCallAction>()

assertEquals(listOf("placeOrder"), actions.map { it.operationId })
assertEquals(listOf(HttpVerb.POST), actions.map { it.verb })
assertEquals(listOf("/store/order"), actions.map { it.path.toString() })
}

private fun buildIndividualFromWorkflow(context: TestContext, workflow: Workflow): RestIndividual {
return context.arazzoService.buildIndividualFromWorkflow(workflow)
}

private fun createTestContext(): TestContext {
val openApiPath = testResourcePath("openapi/pet-coupons-openapi.yaml")
val arazzoPath = testResourcePath("arazzo/pet-coupons-arazzo.yaml")

val sutInfo = SutInfoDto()
sutInfo.baseUrlOfSUT = "http://localhost:8080"
sutInfo.restProblem = RestProblemDto()
sutInfo.restProblem.openApiUrl = openApiPath
sutInfo.defaultOutputFormat = SutInfoDto.OutputFormat.JAVA_JUNIT_4

val controllerInfo = ControllerInfoDto()

val args = listOf(
"--blackBox", "false",
"--seed", "42",
"--enableArazzoWorkflowSampling", "true",
"--arazzoLocation", arazzoPath,
"--probOfArazzoSampling", "1.0",
)

val injector = getInjector(sutInfo, controllerInfo, args)
return TestContext(
sampler = injector.getInstance(RestSampler::class.java),
arazzoService = injector.getInstance(ArazzoWorkflowsService::class.java),
)
}

private fun testResourcePath(relativePath: String): String {
val file = File("../../../core/src/test/resources/$relativePath")
check(file.exists()) { "Missing test resource: ${file.absolutePath}" }
return file.absolutePath
}

private fun checkInvariant(ind: Individual) {
assertTrue(ind.isInitialized(), "Sampled individual is not initialized")
assertTrue(ind.areValidActionLocalIds(), "Sampled individual should have action components which have valid local ids")

val actions = ind.seeAllActions()

for(a in actions){

val topGenes = a.seeTopGenes()
for(tg in topGenes) {
assertTrue(tg.isLocallyValid())
assertTrue(tg.parent !is Gene)
}
}
}

private fun getInjector(
sutInfoDto: SutInfoDto,
controllerInfoDto: ControllerInfoDto,
args: List<String>,
): Injector {
val base = BaseModule(args.toTypedArray())
val problemModule = RestModule(bindRemote = false)
val faker = FakeModule(sutInfoDto, controllerInfoDto)

return LifecycleInjector.builder()
.withModules(base, problemModule, faker)
.build()
.createInjector()
}

private class FakeModule(val sutInfoDto: SutInfoDto?,
val controllerInfoDto: ControllerInfoDto?) : AbstractModule() {
@Provides
@Singleton
fun getRemoteController(): RemoteController {
return FakeRemoteController(sutInfoDto, controllerInfoDto)
}
}

private class FakeRemoteController(
val sutInfoDto: SutInfoDto?,
val controllerInfoDto: ControllerInfoDto?) : RemoteController {
override fun executeDatabaseCommand(dto: DatabaseCommandDto): Boolean {
return true
}

override fun executeDatabaseCommandAndGetQueryResults(dto: DatabaseCommandDto): QueryResultDto? {
return null
}

override fun executeDatabaseInsertionsAndGetIdMapping(dto: DatabaseCommandDto): InsertionResultsDto? {
return null
}

override fun executeMongoDatabaseInsertions(dto: MongoDatabaseCommandDto): MongoInsertionResultsDto? {
return null
}

override fun executeRedisDatabaseInsertions(dto: RedisDatabaseCommandsDto): RedisInsertionResultsDto? {
return null
}

override fun getSutInfo(): SutInfoDto? {
return sutInfoDto
}

override fun getControllerInfo(): ControllerInfoDto? {
return controllerInfoDto
}

override fun startSUT(): Boolean {
return true
}

override fun stopSUT(): Boolean {
return true
}

override fun resetSUT(): Boolean {
return true
}

override fun checkConnection() {
}

override fun startANewSearch(): Boolean {
return true
}

override fun getTestResults(ids: Set<Int>,
ignoreKillSwitch: Boolean,
fullyCovered: Boolean,
descriptiveIds: Boolean): TestResultsDto? {
return null
}

override fun executeNewRPCActionAndGetResponse(actionDto: ActionDto): ActionResponseDto? {
return null
}

override fun postSearchAction(postSearchActionDto: PostSearchActionDto): Boolean {
return true
}

override fun registerNewAction(actionDto: ActionDto): Boolean {
return true
}

override fun address(): String {
return "localhost:40100"
}

override fun close() {
}

override fun deriveParams(deriveParams: List<DerivedParamChangeReqDto>): List<DeriveParamResponseDto> {
return listOf()
}

override fun invokeScheduleTasksAndGetResults(dtos: ScheduleTaskInvocationsDto): ScheduleTaskInvocationsResult? {
return null
}
}
}
5 changes: 5 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,11 @@
<scope>test</scope>
</dependency>

<!-- Arazzo Parser from core-extra module -->
<dependency>
<groupId>org.evomaster</groupId>
<artifactId>arazzo-parser</artifactId>
</dependency>

</dependencies>

Expand Down
20 changes: 20 additions & 0 deletions core/src/main/kotlin/org/evomaster/core/EMConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2293,6 +2293,21 @@ class EMConfig {
"Note that resource-based sampling is only applicable for REST problem with MIO algorithm.")
var resourceSampleStrategy = ResourceSamplingStrategy.ConArchive


/**
* Boolean that enables and disables the generation of individuals based on Arazzo Workflows.
*/
@Experimental
@Cfg("Enable workflow-based sampling from an Arazzo document.")
var enableArazzoWorkflowSampling = false

fun isEnabledArazzoSampling() = enableArazzoWorkflowSampling

@Experimental
@Cfg("Probability of controlling the creation of Arazzo individuals.")
@Probability(activating = false)
var probOfArazzoSampling = 0.5

@Cfg("Specify whether to enable resource dependency heuristics, i.e, probOfEnablingResourceDependencyHeuristics > 0.0. " +
"Note that the option is available to be enabled only if resource-based smart sampling is enable. " +
"This option has an effect on sampling multiple resources and mutating a structure of an individual.")
Expand Down Expand Up @@ -3394,6 +3409,11 @@ class EMConfig {
var inferFormatFromNames = false


@Experimental
@ExistingPath(true,false)
@Cfg("arazzo location on disk")
var arazzoLocation = ""

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