Skip to content

Commit

Permalink
fix(#1175): OpenAPI connector enhancements for simulator random messa…
Browse files Browse the repository at this point in the history
…ge generation
  • Loading branch information
Thorsten Schlathoelter authored and bbortt committed Nov 24, 2024
1 parent 0215f4b commit d6c8493
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 60 deletions.
6 changes: 6 additions & 0 deletions connectors/citrus-openapi/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.17.0</version>
<scope>compile</scope>
</dependency>
</dependencies>

<profiles>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ public static void fillMessageFromResponse(OpenApiSpecification openApiSpecifica
}
}
);

}

private static void fillRequiredHeaders(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ private OasModelHelper() {
* @param schema to check
* @return true if given schema is an object.
*/
public static boolean isObjectType(OasSchema schema) {
public static boolean isObjectType(@Nullable OasSchema schema) {
return schema != null && "object".equals(schema.type);
}

Expand All @@ -64,23 +64,23 @@ public static boolean isObjectType(OasSchema schema) {
* @param schema to check
* @return true if given schema is an array.
*/
public static boolean isArrayType(OasSchema schema) {
return "array".equals(schema.type);
public static boolean isArrayType(@Nullable OasSchema schema) {
return schema != null && "array".equals(schema.type);
}

/**
* Determines if given schema is of type object array .
* @param schema to check
* @return true if given schema is an object array.
*/
public static boolean isObjectArrayType(OasSchema schema) {
if (schema == null || !"array".equals(schema.type)) {
public static boolean isObjectArrayType(@Nullable OasSchema schema) {
if (schema == null || !"array".equals(schema.type)) {
return false;
}
Object items = schema.items;
if (items instanceof OasSchema oasSchema) {
if (items instanceof OasSchema oasSchema) {
return isObjectType(oasSchema);
} else if (items instanceof List<?> list) {
} else if (items instanceof List<?> list) {
return list.stream().allMatch(item -> item instanceof OasSchema oasSchema && isObjectType(oasSchema));
}

Expand All @@ -92,7 +92,7 @@ public static boolean isObjectArrayType(OasSchema schema) {
* @param schema to check
* @return true if given schema has a reference.
*/
public static boolean isReferenceType(OasSchema schema) {
public static boolean isReferenceType(@Nullable OasSchema schema) {
return schema != null && schema.$ref != null;
}

Expand Down Expand Up @@ -191,7 +191,6 @@ public static String getReferenceName(String reference) {
public static Optional<OasSchema> getSchema(OasResponse response) {
return delegate(response, Oas20ModelHelper::getSchema, Oas30ModelHelper::getSchema);
}

public static Optional<OasSchema> getParameterSchema(OasParameter parameter) {
return delegate(parameter, Oas20ModelHelper::getParameterSchema, Oas30ModelHelper::getParameterSchema);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ public static List<String> getSchemes(Oas20Document openApiDoc) {

public static String getBasePath(Oas20Document openApiDoc) {
return Optional.ofNullable(openApiDoc.basePath)
.map(basePath -> basePath.startsWith("/") ? basePath : "/" + basePath).orElse("/");
.map(basePath -> basePath.startsWith("/") ? basePath : "/" + basePath).orElse("/");
}

public static Map<String, OasSchema> getSchemaDefinitions(Oas20Document openApiDoc) {
if (openApiDoc == null
|| openApiDoc.definitions == null) {
|| openApiDoc.definitions == null) {
return Collections.emptyMap();
}

Expand All @@ -69,16 +69,16 @@ public static Optional<OasSchema> getSchema(Oas20Response response) {
return Optional.ofNullable(response.schema);
}

public static Optional<OasSchema> getRequestBodySchema(Oas20Document openApiDoc, Oas20Operation operation) {
public static Optional<OasSchema> getRequestBodySchema(@Nullable Oas20Document ignoredOpenApiDoc, Oas20Operation operation) {
if (operation.parameters == null) {
return Optional.empty();
}

final List<OasParameter> operationParameters = operation.parameters;

Optional<OasParameter> body = operationParameters.stream()
.filter(p -> "body".equals(p.in) && p.schema != null)
.findFirst();
.filter(p -> "body".equals(p.in) && p.schema != null)
.findFirst();

return body.map(oasParameter -> (OasSchema) oasParameter.schema);
}
Expand All @@ -91,7 +91,7 @@ public static Optional<String> getRequestContentType(Oas20Operation operation) {
return Optional.empty();
}

public static Collection<String> getResponseTypes(Oas20Operation operation, @Nullable Oas20Response response) {
public static Collection<String> getResponseTypes(Oas20Operation operation,@Nullable Oas20Response ignoredResponse) {
if (operation == null) {
return Collections.emptyList();
}
Expand All @@ -102,11 +102,11 @@ public static Collection<String> getResponseTypes(Oas20Operation operation, @Nul
* Returns the response content for random response generation. Note that this implementation currently only returns {@link MediaType#APPLICATION_JSON_VALUE},
* if this type exists. Otherwise, it will return an empty Optional. The reason for this is, that we cannot safely guess the type other than for JSON.
*
* @param openApiDoc
* @param ignoredOpenApiDoc required to implement quasi interface but ignored in this implementation.
* @param operation
* @return
*/
public static Optional<String> getResponseContentTypeForRandomGeneration(@Nullable Oas20Document openApiDoc, Oas20Operation operation) {
public static Optional<String> getResponseContentTypeForRandomGeneration(@Nullable Oas20Document ignoredOpenApiDoc, Oas20Operation operation) {
if (operation.produces != null) {
for (String mediaType : operation.produces) {
if (MediaType.APPLICATION_JSON_VALUE.equals(mediaType)) {
Expand Down Expand Up @@ -151,7 +151,7 @@ public static Map<String, OasSchema> getHeaders(Oas20Response response) {
}

return response.headers.getHeaders().stream()
.collect(Collectors.toMap(OasHeader::getName, Oas20ModelHelper::getHeaderSchema));
.collect(Collectors.toMap(OasHeader::getName, Oas20ModelHelper::getHeaderSchema));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import io.apicurio.datamodels.openapi.v3.models.Oas30Parameter;
import io.apicurio.datamodels.openapi.v3.models.Oas30RequestBody;
import io.apicurio.datamodels.openapi.v3.models.Oas30Response;
import jakarta.annotation.Nullable;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
Expand Down Expand Up @@ -76,17 +75,17 @@ public static List<String> getSchemes(Oas30Document openApiDoc) {
}

return openApiDoc.servers.stream()
.map(Oas30ModelHelper::resolveUrl)
.map(serverUrl -> {
try {
return new URL(serverUrl).getProtocol();
} catch (MalformedURLException e) {
LOG.warn(String.format(NO_URL_ERROR_MESSAGE, serverUrl));
return null;
}
})
.filter(Objects::nonNull)
.toList();
.map(Oas30ModelHelper::resolveUrl)
.map(serverUrl -> {
try {
return new URL(serverUrl).getProtocol();
} catch (MalformedURLException e) {
LOG.warn(String.format(NO_URL_ERROR_MESSAGE, serverUrl));
return null;
}
})
.filter(Objects::nonNull)
.toList();
}

public static String getBasePath(Oas30Document openApiDoc) {
Expand Down Expand Up @@ -117,8 +116,8 @@ public static Map<String, OasSchema> getSchemaDefinitions(Oas30Document openApiD
}

return openApiDoc.components.schemas.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, Entry::getValue));
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, Entry::getValue));
}

public static Optional<OasSchema> getSchema(Oas30Response response) {
Expand All @@ -128,11 +127,11 @@ public static Optional<OasSchema> getSchema(Oas30Response response) {
}

return content.entrySet()
.stream()
.filter(entry -> !isFormDataMediaType(entry.getKey()))
.filter(entry -> entry.getValue().schema != null)
.map(entry -> (OasSchema) entry.getValue().schema)
.findFirst();
.stream()
.filter(entry -> !isFormDataMediaType(entry.getKey()))
.filter(entry -> entry.getValue().schema != null)
.map(entry -> (OasSchema) entry.getValue().schema)
.findFirst();
}

public static Optional<OasSchema> getRequestBodySchema(Oas30Document openApiDoc, Oas30Operation operation) {
Expand All @@ -143,8 +142,8 @@ public static Optional<OasSchema> getRequestBodySchema(Oas30Document openApiDoc,
Oas30RequestBody bodyToUse = operation.requestBody;

if (openApiDoc.components != null
&& openApiDoc.components.requestBodies != null
&& bodyToUse.$ref != null) {
&& openApiDoc.components.requestBodies != null
&& bodyToUse.$ref != null) {
bodyToUse = openApiDoc.components.requestBodies.get(OasModelHelper.getReferenceName(bodyToUse.$ref));
}

Expand All @@ -153,12 +152,12 @@ public static Optional<OasSchema> getRequestBodySchema(Oas30Document openApiDoc,
}

return bodyToUse.content.entrySet()
.stream()
.filter(entry -> !isFormDataMediaType(entry.getKey()))
.filter(entry -> entry.getValue().schema != null)
.findFirst()
.map(Map.Entry::getValue)
.map(oas30MediaType -> oas30MediaType.schema);
.stream()
.filter(entry -> !isFormDataMediaType(entry.getKey()))
.filter(entry -> entry.getValue().schema != null)
.findFirst()
.map(Map.Entry::getValue)
.map(oas30MediaType -> oas30MediaType.schema);
}

public static Optional<String> getRequestContentType(Oas30Operation operation) {
Expand All @@ -167,13 +166,13 @@ public static Optional<String> getRequestContentType(Oas30Operation operation) {
}

return operation.requestBody.content.entrySet()
.stream()
.filter(entry -> entry.getValue().schema != null)
.map(Map.Entry::getKey)
.findFirst();
.stream()
.filter(entry -> entry.getValue().schema != null)
.map(Map.Entry::getKey)
.findFirst();
}

public static Collection<String> getResponseTypes(@Nullable Oas30Operation operation, Oas30Response response) {
public static Collection<String> getResponseTypes(Oas30Operation operation, Oas30Response response) {
if (operation == null) {
return Collections.emptySet();
}
Expand All @@ -192,12 +191,12 @@ public static Optional<String> getResponseContentTypeForRandomGeneration(Oas30Do
Optional<OasResponse> responseForRandomGeneration = getResponseForRandomGeneration(
openApiDoc, operation);
return responseForRandomGeneration.map(
Oas30Response.class::cast).flatMap(res -> res.content.entrySet()
.stream()
Oas30Response.class::cast).flatMap(res -> res.content.entrySet()
.stream()
.filter(entry -> MediaType.APPLICATION_JSON_VALUE.equals(entry.getKey()))
.filter(entry -> entry.getValue().schema != null)
.map(Map.Entry::getKey)
.findFirst());
.filter(entry -> entry.getValue().schema != null)
.map(Map.Entry::getKey)
.findFirst());
}

public static Optional<OasResponse> getResponseForRandomGeneration(Oas30Document openApiDoc, Oas30Operation operation) {
Expand Down Expand Up @@ -244,9 +243,9 @@ public static Map<String, OasSchema> getRequiredHeaders(Oas30Response response)
}

return response.headers.entrySet()
.stream()
.filter(entry -> Boolean.TRUE.equals(entry.getValue().required))
.collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().schema));
.stream()
.filter(entry -> Boolean.TRUE.equals(entry.getValue().required))
.collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().schema));
}

public static Map<String, OasSchema> getHeaders(Oas30Response response) {
Expand All @@ -255,8 +254,8 @@ public static Map<String, OasSchema> getHeaders(Oas30Response response) {
}

return response.headers.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().schema));
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().schema));
}

private static boolean isFormDataMediaType(String type) {
Expand Down

0 comments on commit d6c8493

Please sign in to comment.