Skip to content
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
4d30c61
First version parser: Only info document Arazzo. Not Working
daniellopera15 Apr 2, 2026
072562e
Read document arazzo
daniellopera15 Apr 2, 2026
f6c0ebb
Validation Arazzo. Incomplete
daniellopera15 Apr 6, 2026
6c43da5
#UP validate workflow and step. Incomplete
daniellopera15 Apr 10, 2026
c5cfff8
Validation with reference and
daniellopera15 Apr 17, 2026
885bd16
Clean Overlay
daniellopera15 Apr 17, 2026
24abb2b
Parser with validation. Not working
daniellopera15 Apr 17, 2026
025a1e0
Arazzo Only Parser. Test not working
daniellopera15 Apr 18, 2026
825738f
Arazzo parser working with references. Without Validations
daniellopera15 Apr 19, 2026
edc5a7e
Resolver refs on inputs in Workflows
daniellopera15 Apr 20, 2026
4428c01
Delete validation and fixes
daniellopera15 Apr 20, 2026
e4d50d7
clean import
daniellopera15 Apr 21, 2026
cf0fb9c
Fix old code
daniellopera15 Apr 21, 2026
cc951d3
Create Parser in module core-extra
daniellopera15 May 1, 2026
ccdf357
Merge branch 'WebFuzzing:master' into feature/arazzo-parser
daniellopera15 May 1, 2026
f2f7161
Clean core of Arazzo Parser
daniellopera15 May 1, 2026
8d614e8
Add @java-docs v1
daniellopera15 May 2, 2026
075f53c
Rename package of Arazzo
daniellopera15 Jun 26, 2026
03fd9c5
Fix refactor package
daniellopera15 Jun 27, 2026
d1783d1
Review PR V1
daniellopera15 Jun 27, 2026
86bd83d
Update EvoMaster
daniellopera15 Jun 27, 2026
714a8ac
Update Juni 4 to 5 in ArazzoParser
daniellopera15 Jun 27, 2026
cf6f033
Revert changes core/pom.xml
daniellopera15 Jun 27, 2026
10f0ff4
Review PR V2
daniellopera15 Jun 27, 2026
03cd6ab
Review PR V3
daniellopera15 Jun 28, 2026
dbe070f
Review PR V4
daniellopera15 Jun 28, 2026
796be29
Rename DTO's to Unresolved
daniellopera15 Jul 1, 2026
c4e7dce
Merge branch 'master' into feature/arazzo-parser
daniellopera15 Jul 8, 2026
8a452ec
Update Evomaster 6.1.2
daniellopera15 Jul 8, 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ Migrations/
/core-tests/client-java/distance-heuristics/target/
/em.toml

/core-extra/arazzo-parser/target/
/core-extra/solver/target/
/em.yaml
/core-tests/e2e-tests/spring/spring-rest-openapi-v2/em.yaml
Expand Down
84 changes: 84 additions & 0 deletions core-extra/arazzo-parser/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.evomaster</groupId>
<artifactId>evomaster-core-extra</artifactId>
<version>5.1.1-SNAPSHOT</version>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update to 6.0.1-SNAPSHOT

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

</parent>

<artifactId>arazzo-parser</artifactId>

<dependencies>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-models</artifactId>
<version>2.2.34</version>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this version should not be here, but in a parent pom, where other swagger dependency are declared, ie., core-parent/pom.xml

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.mock-server</groupId>
<artifactId>mockserver-client-java-no-dependencies</artifactId>
<scope>compile</scope>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why a compile dependency for this?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This dependency was removed because it had been added during a previous implementation of the tests that ultimately went unused.

</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-core</artifactId>
<version>2.2.34</version>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use properties for repeated version numbers in the same dependency family

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock-jre8-standalone</artifactId>
<scope>compile</scope>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why compile?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This dependency was removed because it had been added during a previous implementation of the tests that ultimately went unused.

</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why old JUnit? doesn't 5 works on JDK 8 as well? (should not use 6 though)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

<scope>test</scope>
</dependency>
<dependency>
<groupId>io.swagger.parser.v3</groupId>
<artifactId>swagger-parser-v3</artifactId>
<version>2.1.33</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>java-dataloader</artifactId>
<version>2.2.3</version>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all these version numbers should not be here. maybe in future we ll put back, but only if we move this library out of EM

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<release>8</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>@{argLine} -ea -Xms512m -Xmx1536m -Xss2m -Dfile.encoding=UTF-8 -Duser.language=en -Duser.country=GB</argLine>
</configuration>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.evomaster.arazzo.access;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename package from org.evomaster.arazzo to com.webfuzzing.arazzo

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
* Read Arrazzo documents
*/
public class ArazzoAccess {
public static String readFromDisk(String arazzoLocation) throws Exception {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do not use Checked Exception declaration, ie remove throws Exception

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, for public methods, should add some JavaDoc

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

String fileScheme = "file:";

Path path;
try {
if (arazzoLocation.toLowerCase().startsWith(fileScheme)) {
path = Paths.get(URI.create(arazzoLocation));
} else {
path = Paths.get(arazzoLocation);
}
} catch (Exception e) {
throw new Exception("The file path provided for the Arazzo Schema " + arazzoLocation + " ended up with the following error: " + e.getMessage());

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IllegalArgumentException

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}

if ((!Files.exists(path))) {
throw new Exception("The provided Arazzo file does not exist: " + arazzoLocation);
}

try {
byte[] bytes = Files.readAllBytes(path);
return new String(bytes, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new Exception("Error reading the Arazzo file: " + e.getMessage());

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RuntimeException

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.evomaster.arazzo.deserializer;

import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import org.evomaster.arazzo.models.domain.AnyExpression;

import java.io.IOException;

/**
* Custom Jackson deserializer for {@link AnyExpression}.
* It resolves dynamic JSON payloads by mapping plain text to a {@link AnyExpression.Expression},
* and any other complex structure to a generic JSON node.
*/
public class AnyExpressionDeserializer extends JsonDeserializer<AnyExpression> {

@Override
public AnyExpression deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser);

if (node.isTextual()) {
return new AnyExpression.Expression(node.asText());
}
JsonNode any = jsonParser.getCodec().treeToValue(node, JsonNode.class);
return new AnyExpression.Any(any);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.evomaster.arazzo.deserializer;

import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import org.evomaster.arazzo.models.domain.CriterionExpression;
import org.evomaster.arazzo.models.domain.CriterionType;

import java.io.IOException;

/**
* Custom Jackson deserializer for {@link CriterionType}.
* It resolves dynamic JSON payloads by mapping plain text to a {@link CriterionType.Simple},
* and a JSON object to a {@link CriterionType.Complex}.
*/
public class CriterionTypeDeserializer extends JsonDeserializer<CriterionType> {

@Override
public CriterionType deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser);

if (node.isTextual()) {
return new CriterionType.Simple(node.asText());
} else if (node.isObject()) {
CriterionExpression complex = jsonParser.getCodec().treeToValue(node, CriterionExpression.class);
return new CriterionType.Complex(complex);
} else {
throw new IllegalArgumentException("Arazzo Parsing Error: Invalid " + node.getNodeType() + ". Expected string or Criterion Expression");
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.evomaster.arazzo.deserializer;

import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import org.evomaster.arazzo.models.domain.*;

import java.io.IOException;

/**
* Custom Jackson deserializer for {@link FailureReusable}.
* It differentiates the incoming JSON payload based on the presence of the "reference" field,
* mapping it to a {@link FailureReusable.ReusableObj} if present, or to a {@link FailureReusable.Failure} otherwise.
*/
public class FailureReusableDeserializer extends JsonDeserializer<FailureReusable> {

@Override
public FailureReusable deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser);

if (node.has("reference")) {
Reusable reusable = jsonParser.getCodec().treeToValue(node, Reusable.class);
return new FailureReusable.ReusableObj(reusable);
}

FailureAction action = jsonParser.getCodec().treeToValue(node, FailureAction.class);
return new FailureReusable.Failure(action);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.evomaster.arazzo.deserializer;

import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import org.evomaster.arazzo.models.domain.*;

import java.io.IOException;

/**
* Custom Jackson deserializer for {@link ParameterReusable}.
* It differentiates the incoming JSON payload based on the presence of the "reference" field,
* mapping it to a {@link ParameterReusable.ReusableObj} if present, or to a {@link ParameterReusable.Param} otherwise.
*/
public class ParameterReusableDeserializer extends JsonDeserializer<ParameterReusable> {

@Override
public ParameterReusable deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser);

if (node.has("reference")) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this "reference", as it is used in different files, should be put in some common constant somewhere

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Reusable reusable = jsonParser.getCodec().treeToValue(node, Reusable.class);
return new ParameterReusable.ReusableObj(reusable);
}

Parameter parameter = jsonParser.getCodec().treeToValue(node, Parameter.class);
return new ParameterReusable.Param(parameter);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.evomaster.arazzo.deserializer;

import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import org.evomaster.arazzo.models.domain.ParameterReusable;
import org.evomaster.arazzo.models.domain.Reusable;
import org.evomaster.arazzo.models.domain.SuccessAction;
import org.evomaster.arazzo.models.domain.SuccessReusable;

import java.io.IOException;

/**
* Custom Jackson deserializer for {@link SuccessReusable}.
* It differentiates the incoming JSON payload based on the presence of the "reference" field,
* mapping it to a {@link SuccessReusable.ReusableObj} if present, or to a {@link SuccessReusable.Success} otherwise.
*/
public class SuccessReusableDeserializer extends JsonDeserializer<SuccessReusable> {

@Override
public SuccessReusable deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser);

if (node.has("reference")) {
Reusable reusable = jsonParser.getCodec().treeToValue(node, Reusable.class);
return new SuccessReusable.ReusableObj(reusable);
}

SuccessAction action = jsonParser.getCodec().treeToValue(node, SuccessAction.class);
return new SuccessReusable.Success(action);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package org.evomaster.arazzo.mapper;

import org.evomaster.arazzo.models.domain.ArazzoSpecifications;
import org.evomaster.arazzo.models.domain.Step;
import org.evomaster.arazzo.models.domain.Workflow;
import org.evomaster.arazzo.models.dto.ArazzoSpecificationsDTO;
import org.evomaster.arazzo.models.dto.StepDTO;
import org.evomaster.arazzo.models.dto.WorkflowDTO;
import org.evomaster.arazzo.resolver.ArazzoReferenceResolver;
import io.swagger.v3.oas.models.media.Schema;

import java.util.Map;
import java.util.stream.Collectors;

/**
* Mapper class responsible for converting Arazzo Specification (DTOs)
* into their corresponding domain models.
*/
public class ArazzoMapper {
private ArazzoReferenceResolver resolver;

public ArazzoMapper(ArazzoReferenceResolver resolver) {
this.resolver = resolver;
}

public ArazzoSpecifications toDomain(ArazzoSpecificationsDTO arazzoSpecificationsDTO) {
return ArazzoSpecifications.builder()
.arazzo(arazzoSpecificationsDTO.getArazzo())
.info(arazzoSpecificationsDTO.getInfo())
.sourceDescriptions(arazzoSpecificationsDTO.getSourceDescriptions())
.workflows(arazzoSpecificationsDTO.getWorkflows().stream()
.map(this::toDomain)
.collect(Collectors.toList()))
.components(arazzoSpecificationsDTO.getComponents())
.build();
}

public Workflow toDomain(WorkflowDTO workflowDTO) {
return Workflow.builder()
.workflowId(workflowDTO.getWorkflowId())
.summary(workflowDTO.getSummary())
.description(workflowDTO.getDescription())
.inputs(this.toDomain(workflowDTO.getInputs()))
.dependsOn(workflowDTO.getDependsOn())
.steps(workflowDTO.getSteps().stream()
.map(this::toDomain)
.collect(Collectors.toList()))
.successActions(resolver.resolveSuccessReusable(workflowDTO.getSuccessActions()))
.failureActions(resolver.resolveFailureReusable(workflowDTO.getFailureActions()))
.outputs(workflowDTO.getOutputs())
.parameters(resolver.resolveParametersReusable(workflowDTO.getParameters()))
.build();
}

public Step toDomain(StepDTO stepDTO) {
return Step.builder()
.description(stepDTO.getDescription())
.stepId(stepDTO.getStepId())
.operationId(stepDTO.getOperationId())
.operationPath(stepDTO.getOperationPath())
.workflowId(stepDTO.getWorkflowId())
.parameters(resolver.resolveParametersReusable(stepDTO.getParameters()))
.requestBody(stepDTO.getRequestBody())
.successCriteria(stepDTO.getSuccessCriteria())
.onSuccess(resolver.resolveSuccessReusable(stepDTO.getOnSuccess()))
.onFailure(resolver.resolveFailureReusable(stepDTO.getOnFailure()))
.outputs(stepDTO.getOutputs())
.build();
}

public Schema<?> toDomain(Schema<?> schema) {
if (schema != null && schema.get$ref() != null && !schema.get$ref().trim().isEmpty()) {
Schema<?> reference = toDomain(resolver.resolveJsonPointer(schema.get$ref()));
if (reference != null) {
if (reference.getProperties() != null) {
Map<String, Schema> updatedProperties = reference.getProperties().entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey, entry -> toDomain(entry.getValue())
));

reference.setProperties(updatedProperties);
}

return reference;
}
}

return schema;
}
}
Loading